Skip to content

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 for middleware behavior and Reverse proxy for general proxy requirements.


Quick checklist

#CheckExpected
1Browser hostnameadmin.* or img.*; do not mix IP / pages.dev
2Pages / Worker in the middleImage host must not fetch(admin…)
3Reverse-proxy upstreamBoth hostnames → http://127.0.0.1:6892
4Nginx proxy_set_header Host$host (preserve client hostname)
5PicHost settingsSITE_BASE_URL / IMAGE_BASE_URL match server_name
6Port 6892Reachable only from localhost or internal proxy

Both hostnames go through Cloudflare (proxied) and independently reverse-proxy to one PicHost instance:

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

HostnameServes
admin.example.comAdmin UI, login, settings, gallery, API, upload
img.example.comImage 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

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:

PreferAvoid
img.example.comWorker Route → existing img originimg → Worker → fetch(admin.example.com)

Cloudflare recommends Routes when an external origin already exists, rather than 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 only.


Two-layer Host protection

Use reverse proxy and application layers together:

LayerRole
Nginx default serverReject 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?