diff --git a/.env.example b/.env.example index 37a738b..b98f0e1 100644 --- a/.env.example +++ b/.env.example @@ -10,12 +10,12 @@ DOMAIN=66.hyf2.cc # Let's Encrypt 申请证书邮箱 ACME_EMAIL=932465777@qq.com -# 管理面板登录(安装完成后访问 http://域名/PANEL_PATH/) +# 管理面板登录(安装完成后访问 https://域名/PANEL_PATH/) PANEL_USERNAME=dekun PANEL_PASSWORD=Woaini521@ # 面板访问路径(留空则安装时自动生成随机路径,如 jiedian-a1b2c3d4) -# 访问示例:http://66.hyf2.cc/jiedian-a1b2c3d4/ +# 访问示例:https://66.hyf2.cc/jiedian-a1b2c3d4/ # PANEL_PATH=jiedian-a1b2c3d4 # 可选:仅允许指定 IP 访问面板(留空则不限制) diff --git a/README.md b/README.md index 4a2ea1c..c11f7ee 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,8 @@ bash scripts/install.sh ## 架构 ``` -浏览器 ──► Nginx:80// ──► Web 管理面板 +浏览器 ──► Nginx:443 HTTPS// ──► Web 管理面板 + └─► Nginx:80(ACME 验证 + 跳转 HTTPS) │ ▼ render-server.py @@ -66,10 +67,11 @@ bash scripts/install.sh | 端口 | 协议 | 用途 | |------|------|------| | 22 | TCP | SSH | -| 80 | TCP | HTTP(ACME + 管理面板) | +| 80 | TCP | HTTP(ACME 证书验证 + 跳转 HTTPS) | +| 443 | TCP | **HTTPS 管理面板** | | 8443–8499 | UDP | Hysteria2(每节点递增) | -云厂商安全组需放行 **8443–8499/UDP**。 +云厂商安全组需放行 **443/TCP** 与 **8443–8499/UDP**。 --- @@ -103,7 +105,8 @@ bash scripts/remove-vless.sh ├── scripts/ │ ├── install.sh # 一键部署 │ ├── uninstall.sh # 卸载 -│ ├── remove-vless.sh # 旧版停用 VLESS +│ ├── remove-vless.sh # 旧版停用 VLESS +│ ├── enable-panel-https.sh # 启用 HTTPS 面板 │ ├── generate-keys.sh # 生成/重置面板密码 │ └── render-server.py # 生成 sing-box 配置 └── docs/ # 文档 diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index 961a2a9..2c2af69 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -8,7 +8,7 @@ | 部署目录 | `/opt/jiedian` | | 系统要求 | Ubuntu 22.04 / 24.04(root 或 sudo) | | 协议 | Hysteria2(UDP 8443+) | -| 管理面板 | `http://域名//`(**HTTP 80,不要用 HTTPS 访问面板**) | +| 管理面板 | `https://域名//`(安装完成后输出;HTTP 80 自动跳转) | --- @@ -43,7 +43,8 @@ dig +short A your.domain.com | 端口 | 协议 | 用途 | 必须 | |------|------|------|------| | 22 | TCP | SSH | 是 | -| 80 | TCP | ACME 证书验证 + 管理面板 | 是 | +| 80 | TCP | ACME 证书验证 | 是 | +| 443 | TCP | **HTTPS 管理面板** | 是 | | 8443–8499 | UDP | Hysteria2(多节点递增) | 是 | > **重要**:每增加一个节点,Hy2 端口 +1(8443、8444、8445…)。安全组必须放行 **8443–8499/UDP** 整段,不能只开 8443。 @@ -87,16 +88,17 @@ bash scripts/install.sh 安装脚本会自动完成: 1. 安装 sing-box、nginx、Python 面板依赖 -2. 配置 UFW 防火墙(22/80 TCP,8443–8499 UDP) +2. 配置 UFW 防火墙(22/80/443 TCP,8443–8499 UDP) 3. 通过 acme.sh 为 `DOMAIN` 申请 TLS 证书 4. 初始化 SQLite 节点库与默认管理员 -5. 生成 sing-box 配置并启动服务 +5. 生成 sing-box 配置、启用 **HTTPS 面板**并启动服务 安装结束输出示例: ``` ========================================== - 管理面板: http://66.hyf2.cc/jiedian-xxxx/ + 管理面板: https://66.hyf2.cc/jiedian-xxxx/ + (HTTP 会自动跳转到 HTTPS) 面板路径: jiedian-xxxx 用户名: dekun 密码: xxxxx @@ -121,9 +123,9 @@ sing-box check -c /etc/sing-box/config.json # Hy2 端口监听(默认 8443,多节点还有 8444…) ss -ulnp | grep 8443 -# 面板可访问 +# 面板 HTTPS 可访问(应返回 200/302) PANEL_PATH=$(grep ^PANEL_PATH= /opt/jiedian/.env | cut -d= -f2) -curl -I "http://$(grep ^DOMAIN= /opt/jiedian/.env | cut -d= -f2)/${PANEL_PATH}/login" +curl -Ik "https://$(grep ^DOMAIN= /opt/jiedian/.env | cut -d= -f2)/${PANEL_PATH}/login" ``` 客户端导入 Hy2 链接后测速,应显示正常延迟(非 `-1`)。 @@ -153,10 +155,18 @@ sudo bash scripts/remove-vless.sh - 停止并禁用 Xray - 重载 sing-box 配置 +- **启用 HTTPS 管理面板(443)** - 重启面板 -- 删除防火墙 443 规则(可选) -完成后客户端 **删除所有 VLESS 节点**,仅从面板复制 `hy2://` 链接。 +完成后客户端 **删除所有 VLESS 节点**,从面板复制 `hy2://` 链接,并用 **HTTPS** 登录面板。 + +### 已有 VPS 仅升级 HTTPS 面板 + +```bash +cd /opt/jiedian && git pull +sudo bash scripts/enable-panel-https.sh +systemctl restart jiedian-panel +``` --- @@ -186,7 +196,8 @@ bash scripts/install.sh ## 七、架构说明 ``` -浏览器 ──► Nginx:80// ──► Flask 管理面板 +浏览器 ──► Nginx:443 HTTPS// ──► Flask 管理面板 + └─► Nginx:80(ACME + 跳转 HTTPS) │ ▼ render-server.py diff --git a/docs/GUIDE.md b/docs/GUIDE.md index f1a8f79..1aad983 100644 --- a/docs/GUIDE.md +++ b/docs/GUIDE.md @@ -21,11 +21,12 @@ ### 访问地址 ``` -http://你的域名// +https://你的域名// ``` -- 必须使用 **HTTP**(端口 80),不要用 HTTPS -- `PANEL_PATH` 在安装时生成,保存在 VPS 的 `/opt/jiedian/.env` 中: +- 使用 **HTTPS**(443 端口),密码加密传输 +- 若输入 `http://` 会自动跳转到 HTTPS +- `PANEL_PATH` 在 `/opt/jiedian/.env` 中: ```bash grep PANEL_PATH /opt/jiedian/.env diff --git a/docs/README.md b/docs/README.md index 858839d..094b493 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,5 +12,6 @@ - 仓库:https://git.bz121.com/dekun/jiedian.git - 部署目录:`/opt/jiedian` -- 一键安装:`bash scripts/install.sh` +- 一键安装:`bash scripts/install.sh`(自动 HTTPS 面板) - 旧版去 VLESS:`bash scripts/remove-vless.sh` +- 单独启用 HTTPS:`bash scripts/enable-panel-https.sh` diff --git a/docs/STACK.md b/docs/STACK.md index 0494353..6c6820e 100644 --- a/docs/STACK.md +++ b/docs/STACK.md @@ -12,7 +12,8 @@ | 端口 | 协议 | 进程 | 说明 | |------|------|------|------| -| 80 | TCP | Nginx | ACME + 面板 | +| 80 | TCP | Nginx | ACME 验证 + 跳转 HTTPS | +| 443 | TCP | Nginx | **HTTPS 管理面板** | | 8443–8499 | UDP | sing-box | Hy2,每节点 +1 | ## 配置生成 diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index b852ca2..b5b0552 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -31,15 +31,23 @@ ss -tlnp | grep :80 # Nginx 面板 | SNI | 与域名相同 | | 端口 | 面板显示的端口(8443 / 8444…) | -### 面板打不开 / Invalid URL +### 面板打不开 -- 使用 **`http://域名/PANEL_PATH/`**,不要用 `https://` -- 面板在 **80** 端口,不是 443 -- 域名建议 **关闭 CDN**,仅 DNS 解析到 VPS +- 使用 **`https://域名/PANEL_PATH/`** 登录(推荐) +- 输入 `http://` 也会自动跳转到 HTTPS +- 安全组需放行 **443/TCP** 与 **80/TCP**(ACME 续期) ```bash grep PANEL_PATH /opt/jiedian/.env -curl -I "http://$(grep ^DOMAIN= /opt/jiedian/.env | cut -d= -f2)/$(grep ^PANEL_PATH= /opt/jiedian/.env | cut -d= -f2)/login" +curl -Ik "https://$(grep ^DOMAIN= /opt/jiedian/.env | cut -d= -f2)/$(grep ^PANEL_PATH= /opt/jiedian/.env | cut -d= -f2)/login" +``` + +### 旧 VPS 升级 HTTPS 面板 + +```bash +cd /opt/jiedian && git pull +sudo bash scripts/enable-panel-https.sh +systemctl restart jiedian-panel ``` ### 多节点全部显示离线 @@ -81,7 +89,8 @@ systemctl restart jiedian-panel | 端口 | 协议 | 用途 | |------|------|------| | 22 | TCP | SSH | -| 80 | TCP | 面板 + ACME | +| 80 | TCP | ACME 续期 | +| 443 | TCP | HTTPS 管理面板 | | 8443–8499 | UDP | Hysteria2 | --- diff --git a/panel/app.py b/panel/app.py index 143385e..4a72c17 100644 --- a/panel/app.py +++ b/panel/app.py @@ -52,7 +52,8 @@ _panel_path = os.environ.get("PANEL_PATH", "").strip().strip("/") _panel_domain = os.environ.get("PANEL_DOMAIN", "").strip() if _panel_path: app.config["SESSION_COOKIE_PATH"] = f"/{_panel_path}/" - app.config["PREFERRED_URL_SCHEME"] = "http" + app.config["PREFERRED_URL_SCHEME"] = "https" + app.config["SESSION_COOKIE_SECURE"] = True app.wsgi_app = ProxyFix( app.wsgi_app, x_for=1, x_proto=1, x_host=0, x_prefix=0 ) @@ -71,7 +72,7 @@ class _PanelPrefixMiddleware: if self.domain and not environ.get("HTTP_HOST"): environ["HTTP_HOST"] = self.domain if not environ.get("HTTP_X_FORWARDED_PROTO"): - environ["HTTP_X_FORWARDED_PROTO"] = "http" + environ["HTTP_X_FORWARDED_PROTO"] = "https" return self.app(environ, start_response) diff --git a/scripts/enable-panel-https.sh b/scripts/enable-panel-https.sh new file mode 100644 index 0000000..a6fff65 --- /dev/null +++ b/scripts/enable-panel-https.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# 为管理面板启用 Nginx HTTPS(443);install.sh 与新装/升级后调用 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +ENV_FILE="${ROOT_DIR}/.env" + +[[ -f "$ENV_FILE" ]] || { echo "缺少 $ENV_FILE"; exit 1; } +# shellcheck disable=SC1090 +source "$ENV_FILE" + +: "${DOMAIN:?}" +: "${VPS_IP:?}" + +normalize_panel_path() { + local p="${1:-}" + p="${p#/}" + p="${p%/}" + echo "$p" +} + +PANEL_PATH="$(normalize_panel_path "${PANEL_PATH:-}")" +if [[ -z "$PANEL_PATH" ]]; then + echo "缺少 PANEL_PATH,请先运行 install.sh 或写入 .env" + exit 1 +fi + +PANEL_LOCATION="/${PANEL_PATH}/" +PANEL_PREFIX="/${PANEL_PATH}" + +PANEL_ALLOW_BLOCK="" +if [[ -n "${PANEL_ALLOW_IP:-}" ]]; then + PANEL_ALLOW_BLOCK=" allow ${PANEL_ALLOW_IP}; + deny all;" +fi + +if [[ ! -f /etc/sing-box/certs/fullchain.pem ]] || [[ ! -f /etc/sing-box/certs/privkey.pem ]]; then + echo "缺少 TLS 证书,请先完成 install.sh 或 acme.sh 申请证书" + exit 1 +fi + +if command -v ufw &>/dev/null; then + ufw allow 443/tcp comment 'Panel-HTTPS' 2>/dev/null || true +fi + +sed -e "s|__DOMAIN__|${DOMAIN}|g" \ + -e "s|__PANEL_LOCATION__|${PANEL_LOCATION}|g" \ + -e "s|__PANEL_PREFIX__|${PANEL_PREFIX}|g" \ + -e "s|__PANEL_ALLOW__|${PANEL_ALLOW_BLOCK}|g" \ + "$ROOT_DIR/server/nginx/panel.conf.template" \ + > /etc/nginx/sites-available/jiedian-panel + +ln -sf /etc/nginx/sites-available/jiedian-panel /etc/nginx/sites-enabled/jiedian-panel +rm -f /etc/nginx/sites-enabled/acme + +nginx -t +systemctl reload nginx + +echo "面板 HTTPS 已启用: https://${DOMAIN}${PANEL_LOCATION}" diff --git a/scripts/install.sh b/scripts/install.sh index a3707a0..d945c10 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -115,7 +115,8 @@ ufw --force reset ufw default deny incoming ufw default allow outgoing ufw allow 22/tcp comment 'SSH' -ufw allow 80/tcp comment 'HTTP-ACME-Panel' +ufw allow 80/tcp comment 'HTTP-ACME' +ufw allow 443/tcp comment 'Panel-HTTPS' ufw allow 8443:8499/udp comment 'Hysteria2-multi-node' ufw --force enable @@ -126,13 +127,10 @@ cp "$ROOT_DIR/server/nginx/fallback.conf" /etc/nginx/sites-available/fallback ln -sf /etc/nginx/sites-available/fallback /etc/nginx/sites-enabled/fallback rm -f /etc/nginx/sites-enabled/default -log "部署 Nginx ACME + 管理面板反向代理 (80) ..." +log "部署 Nginx ACME 验证站点 (80) ..." mkdir -p /var/www/acme sed -e "s|__DOMAIN__|${DOMAIN}|g" \ - -e "s|__PANEL_LOCATION__|${PANEL_LOCATION}|g" \ - -e "s|__PANEL_PREFIX__|${PANEL_PREFIX}|g" \ - -e "s|__PANEL_ALLOW__|${PANEL_ALLOW_BLOCK}|g" \ - "$ROOT_DIR/server/nginx/acme.conf.template" \ + "$ROOT_DIR/server/nginx/acme-bootstrap.conf.template" \ > /etc/nginx/sites-available/acme ln -sf /etc/nginx/sites-available/acme /etc/nginx/sites-enabled/acme nginx -t && systemctl enable nginx && systemctl restart nginx @@ -160,8 +158,10 @@ log "安装 TLS 证书到 sing-box ..." --key-file /etc/sing-box/certs/privkey.pem \ --fullchain-file /etc/sing-box/certs/fullchain.pem +log "部署 Nginx HTTPS 管理面板 (443) ..." +bash "$ROOT_DIR/scripts/enable-panel-https.sh" + rm -f /etc/nginx/sites-enabled/panel /etc/nginx/sites-available/panel -nginx -t && systemctl reload nginx log "安装 Python 面板依赖 ..." python3 -m venv "$ROOT_DIR/panel/venv" @@ -229,7 +229,8 @@ systemctl restart sing-box jiedian-panel log "部署完成!" echo "" echo "==========================================" -echo " 管理面板: http://${DOMAIN}${PANEL_LOCATION}" +echo " 管理面板: https://${DOMAIN}${PANEL_LOCATION}" +echo " (HTTP 会自动跳转到 HTTPS)" echo " 面板路径: ${PANEL_PATH} (见 .env 中 PANEL_PATH)" echo " 用户名: ${PANEL_USERNAME}" echo " 密码: ${PANEL_PASSWORD}" diff --git a/scripts/remove-vless.sh b/scripts/remove-vless.sh index d17daa8..65553a3 100644 --- a/scripts/remove-vless.sh +++ b/scripts/remove-vless.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# 已有 VPS:停用 Xray/VLESS,仅保留 Hysteria2 +# 已有 VPS:停用 Xray/VLESS,并启用 HTTPS 管理面板 set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" @@ -8,22 +8,24 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" export JIEDIAN_ROOT="$ROOT" -echo "[1/4] 停止并禁用 Xray ..." +echo "[1/5] 停止并禁用 Xray ..." systemctl stop xray 2>/dev/null || true systemctl disable xray 2>/dev/null || true -echo "[2/4] 更新代码并重载 sing-box 配置 ..." +echo "[2/5] 更新代码 ..." if [[ -d "$ROOT/.git" ]]; then git -C "$ROOT" pull --ff-only || echo "(git pull 跳过,请手动同步)" fi + +echo "[3/5] 重载 sing-box 配置 ..." python3 "$ROOT/scripts/render-server.py" -echo "[3/4] 重启服务 ..." +echo "[4/5] 启用 HTTPS 管理面板 ..." +bash "$ROOT/scripts/enable-panel-https.sh" + +echo "[5/5] 重启服务 ..." systemctl restart sing-box jiedian-panel -echo "[4/4] 可选:关闭防火墙 443(若不再需要) ..." -ufw delete allow 443/tcp 2>/dev/null || true - echo "" -echo "完成。VLESS 已停用,面板仅显示 Hysteria2 链接。" +echo "完成。VLESS 已停用,面板请用 HTTPS 访问。" echo "客户端请删除旧 VLESS 节点,从面板复制 hy2:// 链接导入。" diff --git a/server/nginx/acme-bootstrap.conf.template b/server/nginx/acme-bootstrap.conf.template new file mode 100644 index 0000000..67cf235 --- /dev/null +++ b/server/nginx/acme-bootstrap.conf.template @@ -0,0 +1,17 @@ +server { + listen 80; + listen [::]:80; + server_name __DOMAIN__; + + root /var/www/acme; + + location /.well-known/acme-challenge/ { + default_type "text/plain"; + try_files $uri =404; + } + + location / { + return 200 'ok'; + add_header Content-Type text/plain; + } +} diff --git a/server/nginx/acme.conf.template b/server/nginx/panel.conf.template similarity index 59% rename from server/nginx/acme.conf.template rename to server/nginx/panel.conf.template index 309253d..bf8487a 100644 --- a/server/nginx/acme.conf.template +++ b/server/nginx/panel.conf.template @@ -1,3 +1,4 @@ +# HTTP:ACME 验证 + 面板跳转 HTTPS server { listen 80; listen [::]:80; @@ -10,12 +11,28 @@ server { try_files $uri =404; } + location ^~ __PANEL_LOCATION__ { + return 301 https://$host$request_uri; + } + location / { return 200 'ok'; add_header Content-Type text/plain; } +} + +# HTTPS:管理面板 +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name __DOMAIN__; + + ssl_certificate /etc/sing-box/certs/fullchain.pem; + ssl_certificate_key /etc/sing-box/certs/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 1d; - # 管理面板(Nginx 反向代理至 Flask,无需额外暴露 8444) location ^~ __PANEL_LOCATION__ { __PANEL_ALLOW__ proxy_pass http://127.0.0.1:5080/; @@ -26,8 +43,12 @@ __PANEL_ALLOW__ proxy_set_header Host __DOMAIN__; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-Host __DOMAIN__; proxy_set_header X-Forwarded-Prefix __PANEL_PREFIX__; } + + location / { + return 404; + } }