fix: prevent [No Host] panel errors behind CDN or missing Host header
Force nginx to pass the domain as Host, add PANEL_DOMAIN fallback in Flask, and document that the admin panel must be accessed over HTTP not HTTPS. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
|------|-----|
|
|------|-----|
|
||||||
| VPS IP | `47.76.87.111` |
|
| VPS IP | `47.76.87.111` |
|
||||||
| 域名 | `66.hyf2.cc` |
|
| 域名 | `66.hyf2.cc` |
|
||||||
| 管理面板 | `http://66.hyf2.cc/<PANEL_PATH>/` |
|
| 管理面板 | `http://66.hyf2.cc/<PANEL_PATH>/`(**必须 http,不要用 https**) |
|
||||||
| 部署目录 | `/opt/jiedian` |
|
| 部署目录 | `/opt/jiedian` |
|
||||||
| 系统 | Ubuntu 22.04 / 24.04 |
|
| 系统 | Ubuntu 22.04 / 24.04 |
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ curl -I "http://66.hyf2.cc/$(grep ^PANEL_PATH= /opt/jiedian/.env | cut -d= -f2)/
|
|||||||
```
|
```
|
||||||
|
|
||||||
> 443 端口已被 sing-box Reality 占用,面板走 80 端口子路径。请妥善保管 `PANEL_PATH`,相当于隐藏入口。
|
> 443 端口已被 sing-box Reality 占用,面板走 80 端口子路径。请妥善保管 `PANEL_PATH`,相当于隐藏入口。
|
||||||
|
>
|
||||||
|
> **必须用 `http://` 访问,不要用 `https://`。** 443 不是 Web 面板,用 HTTPS 会报错或出现 `Invalid URL / [No Host]`。
|
||||||
|
|
||||||
面板可查看每个节点的 **在线状态、连接数、实时速率、累计流量**(数据来自 sing-box Clash API,仅监听 127.0.0.1)。
|
面板可查看每个节点的 **在线状态、连接数、实时速率、累计流量**(数据来自 sing-box Clash API,仅监听 127.0.0.1)。
|
||||||
|
|
||||||
@@ -45,6 +47,33 @@ curl -I "http://66.hyf2.cc/$(grep ^PANEL_PATH= /opt/jiedian/.env | cut -d= -f2)/
|
|||||||
|
|
||||||
## 常见问题
|
## 常见问题
|
||||||
|
|
||||||
|
### 面板报 Invalid URL / [No Host]
|
||||||
|
|
||||||
|
**原因**:用了 `https://域名/面板路径/` 访问,或域名开了 CDN 加速但回源 Host 未配置。
|
||||||
|
|
||||||
|
- 443 端口是 **sing-box Reality**,不是 Web 面板
|
||||||
|
- 面板地址必须是:**`http://66.hyf2.cc/jiedian-xxxx/`**(注意是 **http**)
|
||||||
|
|
||||||
|
**处理**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 用 HTTP 打开(把 jiedian-xxxx 换成你的 PANEL_PATH)
|
||||||
|
http://66.hyf2.cc/jiedian-xxxx/
|
||||||
|
|
||||||
|
# 2. VPS 上更新 nginx 与面板(修复 Host 头)
|
||||||
|
cd /opt/jiedian
|
||||||
|
git pull
|
||||||
|
sed -e "s|__DOMAIN__|$(grep ^DOMAIN= .env | cut -d= -f2)|g" \
|
||||||
|
-e "s|__PANEL_LOCATION__|/$(grep ^PANEL_PATH= .env | cut -d= -f2)/|g" \
|
||||||
|
-e "s|__PANEL_PREFIX__|/$(grep ^PANEL_PATH= .env | cut -d= -f2)|g" \
|
||||||
|
-e "s|__PANEL_ALLOW__||g" \
|
||||||
|
server/nginx/acme.conf.template > /etc/nginx/sites-available/acme
|
||||||
|
nginx -t && systemctl reload nginx
|
||||||
|
systemctl restart jiedian-panel
|
||||||
|
```
|
||||||
|
|
||||||
|
若域名在阿里云/Cloudflare 开了 **CDN 代理**,建议对管理域名 **关闭 CDN**(仅 DNS 解析到 VPS),否则 80 端口回源也可能异常。
|
||||||
|
|
||||||
### sing-box 报错 v2ray api is not included in this build
|
### sing-box 报错 v2ray api is not included in this build
|
||||||
|
|
||||||
GitHub 下载的官方 sing-box **默认不带** `v2ray_api` 模块。若配置里写了 `experimental.v2ray_api`,启动时会直接失败:
|
GitHub 下载的官方 sing-box **默认不带** `v2ray_api` 模块。若配置里写了 `experimental.v2ray_api`,启动时会直接失败:
|
||||||
|
|||||||
+24
-1
@@ -47,9 +47,32 @@ app.config.update(
|
|||||||
)
|
)
|
||||||
|
|
||||||
_panel_path = os.environ.get("PANEL_PATH", "").strip().strip("/")
|
_panel_path = os.environ.get("PANEL_PATH", "").strip().strip("/")
|
||||||
|
_panel_domain = os.environ.get("PANEL_DOMAIN", "").strip()
|
||||||
if _panel_path:
|
if _panel_path:
|
||||||
app.config["SESSION_COOKIE_PATH"] = f"/{_panel_path}/"
|
app.config["SESSION_COOKIE_PATH"] = f"/{_panel_path}/"
|
||||||
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1)
|
app.config["PREFERRED_URL_SCHEME"] = "http"
|
||||||
|
app.wsgi_app = ProxyFix(
|
||||||
|
app.wsgi_app, x_for=1, x_proto=1, x_host=0, x_prefix=1
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class _PanelHostMiddleware:
|
||||||
|
"""CDN/反代未传 Host 时,避免重定向到 http://[No Host]/...。"""
|
||||||
|
|
||||||
|
def __init__(self, app, domain: str):
|
||||||
|
self.app = app
|
||||||
|
self.domain = domain
|
||||||
|
|
||||||
|
def __call__(self, environ, start_response):
|
||||||
|
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"
|
||||||
|
return self.app(environ, start_response)
|
||||||
|
|
||||||
|
|
||||||
|
if _panel_domain:
|
||||||
|
app.wsgi_app = _PanelHostMiddleware(app.wsgi_app, _panel_domain)
|
||||||
|
|
||||||
|
|
||||||
def login_required(view):
|
def login_required(view):
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ Type=simple
|
|||||||
WorkingDirectory=${ROOT_DIR}/panel
|
WorkingDirectory=${ROOT_DIR}/panel
|
||||||
Environment=JIEDIAN_ROOT=${ROOT_DIR}
|
Environment=JIEDIAN_ROOT=${ROOT_DIR}
|
||||||
Environment=PANEL_PATH=${PANEL_PATH}
|
Environment=PANEL_PATH=${PANEL_PATH}
|
||||||
|
Environment=PANEL_DOMAIN=${DOMAIN}
|
||||||
ExecStart=${ROOT_DIR}/panel/venv/bin/python app.py
|
ExecStart=${ROOT_DIR}/panel/venv/bin/python app.py
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
|
|||||||
@@ -20,10 +20,11 @@ server {
|
|||||||
__PANEL_ALLOW__
|
__PANEL_ALLOW__
|
||||||
proxy_pass http://127.0.0.1:5080/;
|
proxy_pass http://127.0.0.1:5080/;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host __DOMAIN__;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Host __DOMAIN__;
|
||||||
proxy_set_header X-Forwarded-Prefix __PANEL_PREFIX__;
|
proxy_set_header X-Forwarded-Prefix __PANEL_PREFIX__;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user