release: v1.2.2 — 双域名配置与 Host 隔离修复
GitHub Release / release (push) Canceled after 0s
Publish Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Canceled after 0s
Publish Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Canceled after 0s
Publish Docker image / merge (push) Canceled after 0s
ci / ci (22, ubuntu-latest) (push) Canceled after 0s
GitHub Release / release (push) Canceled after 0s
Publish Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Canceled after 0s
Publish Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Canceled after 0s
Publish Docker image / merge (push) Canceled after 0s
ci / ci (22, ubuntu-latest) (push) Canceled after 0s
修复设置页误清空管理域、配置与生效 URL 混淆及第三 Host 绕过隔离;加固 Settings API 与中间件,并更新文档站。
This commit is contained in:
1 parent
6c6766221b
commit
c9c34515dd
36 files changed
+2578
-180
No files matched your search
@@ -0,0 +1,236 @@
|
||||
# Cloudflare & preferred-edge deployment
|
||||
|
||||
In dual-domain mode, PicHost distinguishes **site** vs **image** traffic from the request **Host** (and `X-Forwarded-Host` from a trusted reverse proxy). Cloudflare orange cloud, preferred-edge IPs, Workers, and Pages are all fine — as long as the hostname identity reaching PicHost stays correct.
|
||||
|
||||
> **One-line rule:** The network path may change; the hostname identity must not — `admin → admin`, `img → img`, never `img → admin`.
|
||||
|
||||
See [Dual-domain separation](./domain-separation.md) for middleware behavior and [Reverse proxy](./reverse-proxy.md) for general proxy requirements.
|
||||
|
||||
---
|
||||
|
||||
## Quick checklist
|
||||
|
||||
| # | Check | Expected |
|
||||
| - | ----- | -------- |
|
||||
| 1 | Browser hostname | `admin.*` or `img.*`; do not mix IP / `pages.dev` |
|
||||
| 2 | Pages / Worker in the middle | Image host must **not** `fetch(admin…)` |
|
||||
| 3 | Reverse-proxy upstream | Both hostnames → `http://127.0.0.1:6892` |
|
||||
| 4 | Nginx `proxy_set_header Host` | `$host` (preserve client hostname) |
|
||||
| 5 | PicHost settings | `SITE_BASE_URL` / `IMAGE_BASE_URL` match `server_name` |
|
||||
| 6 | Port `6892` | Reachable only from localhost or internal proxy |
|
||||
|
||||
---
|
||||
|
||||
## Recommended layout
|
||||
|
||||
Both hostnames go through Cloudflare (proxied) and **independently** reverse-proxy to one PicHost instance:
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
internet[Internet]
|
||||
cf[Cloudflare proxied]
|
||||
admin[admin.example.com]
|
||||
img[img.example.com]
|
||||
panel[1Panel / Nginx]
|
||||
app[PicHost :6892]
|
||||
|
||||
internet --> cf
|
||||
cf --> admin
|
||||
cf --> img
|
||||
admin --> panel
|
||||
img --> panel
|
||||
panel --> app
|
||||
```
|
||||
|
||||
```env
|
||||
SITE_BASE_URL=https://admin.example.com
|
||||
IMAGE_BASE_URL=https://img.example.com
|
||||
```
|
||||
|
||||
```text
|
||||
admin.example.com → http://127.0.0.1:6892
|
||||
img.example.com → http://127.0.0.1:6892
|
||||
```
|
||||
|
||||
You do **not** need separate ports for “frontend / backend / images” — one PicHost instance on port `6892` is enough.
|
||||
|
||||
### Site hostname ≠ frontend domain
|
||||
|
||||
| Hostname | Serves |
|
||||
| -------- | ------ |
|
||||
| `admin.example.com` | Admin UI, login, settings, gallery, API, upload |
|
||||
| `img.example.com` | Image delivery, hotlinks, CDN |
|
||||
|
||||
Use **site / image hostname**, not “frontend / backend”. PicHost does **not** require `frontend :3000 + backend :6892` in production.
|
||||
|
||||
---
|
||||
|
||||
## Orange cloud & preferred edge
|
||||
|
||||
**DNS Proxied (orange cloud)** is normal and recommended:
|
||||
|
||||
```text
|
||||
admin.example.com, img.example.com
|
||||
A/CNAME → origin → Proxied
|
||||
```
|
||||
|
||||
Opening `admin.example.com` should yield `Host: admin.example.com` at PicHost; `img.example.com` should yield `Host: img.example.com`.
|
||||
|
||||
**Preferred-edge** setups (alternate IPs, entry hostnames) are also fine. Preferred routing may change the path to Cloudflare’s edge, but must **not** rewrite the image hostname’s origin identity to the site hostname:
|
||||
|
||||
```text
|
||||
admin → CF → admin.example.com → origin → PicHost
|
||||
img → CF → img.example.com → origin → PicHost
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Typical bad topologies
|
||||
|
||||
These patterns break Host isolation even when the browser still shows the image hostname:
|
||||
|
||||
### ❌ Bad 1: Image host fetches site host
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
user[User on img.example.com]
|
||||
worker[Pages / Worker]
|
||||
admin[fetch admin.example.com]
|
||||
app[PicHost]
|
||||
|
||||
user --> worker --> admin --> app
|
||||
```
|
||||
|
||||
The last hop has `Host: admin.example.com`, so PicHost treats it as site traffic — `https://img.example.com/` may show the admin UI. This is **Host rewrite**, not a cache bug.
|
||||
|
||||
### ❌ Bad 2: Preferred proxy upstreams to site host
|
||||
|
||||
```text
|
||||
img.example.com → preferred hostname → admin.example.com → origin
|
||||
```
|
||||
|
||||
Even for routing only, using the site hostname as upstream breaks image isolation.
|
||||
|
||||
### ❌ Bad 3: Public exposure of port 6892
|
||||
|
||||
```text
|
||||
any host / IP:6892 → PicHost
|
||||
```
|
||||
|
||||
Users can bypass Cloudflare and Nginx `server_name` rules. Port `6892` should be reachable only from `127.0.0.1` or an internal reverse proxy.
|
||||
|
||||
### ✅ Correct pattern
|
||||
|
||||
```text
|
||||
admin → admin → PicHost
|
||||
img → img → PicHost
|
||||
```
|
||||
|
||||
Do **not** use Pages / Workers as a **full-site reverse proxy** for PicHost (extra `pages.dev` / `workers.dev` entry points). PicHost needs `node-server`, SQLite, `sharp`, and local `data/` — it **cannot** run as a Node app on Pages/Workers. Keep Docker/VPS for the app; use orange-cloud DNS and optional R2 on CF.
|
||||
|
||||
---
|
||||
|
||||
## Workers / Pages guidance
|
||||
|
||||
If you only need headers, auth, Referer rules, logging, or cache — and PicHost remains your origin:
|
||||
|
||||
| Prefer | Avoid |
|
||||
| ------ | ----- |
|
||||
| `img.example.com` → **Worker Route** → existing `img` origin | `img` → Worker → `fetch(admin.example.com)` |
|
||||
|
||||
Cloudflare recommends [Routes](https://developers.cloudflare.com/workers/configuration/routing/routes/) when an external origin already exists, rather than [Custom Domains](https://developers.cloudflare.com/workers/configuration/routing/custom-domains/) used to chain cross-host `fetch()`.
|
||||
|
||||
Code like this on the image hostname is a smoking gun:
|
||||
|
||||
```js
|
||||
fetch(`https://admin.example.com${url.pathname}`)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Nginx / 1Panel layout
|
||||
|
||||
Two `server` blocks, same upstream. Critical line: `proxy_set_header Host $host;`
|
||||
|
||||
```nginx
|
||||
server {
|
||||
server_name admin.example.com;
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:6892;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
client_max_body_size 12m;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
server_name img.example.com;
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:6892;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
|
||||
# Reject bare IP and unknown hostnames (strongly recommended)
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen 443 ssl default_server;
|
||||
server_name _;
|
||||
return 444;
|
||||
}
|
||||
```
|
||||
|
||||
With orange cloud, restrict the origin firewall to **[Cloudflare IP ranges](https://www.cloudflare.com/ips/)** only.
|
||||
|
||||
---
|
||||
|
||||
## Two-layer Host protection
|
||||
|
||||
Use reverse proxy and application layers **together**:
|
||||
|
||||
| Layer | Role |
|
||||
| ----- | ---- |
|
||||
| **Nginx default server** | Reject bare IP, `pages.dev`, and other undeclared hostnames |
|
||||
| **PicHost middleware (v1.2.x+)** | When dual-domain is on, unconfigured hosts get 404 at the app (`localhost` / `127.0.0.1` exempt in development) |
|
||||
|
||||
Even with app-layer blocking, keep a default server at the proxy to reduce junk traffic to PicHost.
|
||||
|
||||
---
|
||||
|
||||
## X-Forwarded-Host
|
||||
|
||||
PicHost may consult `X-Forwarded-Host` behind a reverse proxy, but that header is **forgeable** by clients. Therefore:
|
||||
|
||||
- Do not expose port `6892` publicly
|
||||
- Only trusted proxies should reach the app
|
||||
- Prefer keeping `Host` correct from the first hop
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting: admin UI on image hostname?
|
||||
|
||||
**Inspect the proxy chain first — do not purge CF cache first.**
|
||||
|
||||
Cache issues usually mean stale JS/CSS/images or occasional 404s. If `/`, `/login`, and `/settings` work **reliably** on the image host, the Host was almost certainly rewritten.
|
||||
|
||||
```text
|
||||
① Browser hostname?
|
||||
② Pages / Worker / preferred proxy in the middle?
|
||||
③ What URL does the proxy fetch?
|
||||
④ Does it fetch admin.example.com?
|
||||
⑤ Which Host does 1Panel / PicHost see?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related
|
||||
|
||||
- [Dual-domain separation](./domain-separation.md)
|
||||
- [Reverse proxy](./reverse-proxy.md)
|
||||
- [Environment variables](./configuration.md)
|
||||
- [FAQ](./faq.md)
|
||||
Reference in new issue
Block a user