用自建的 frp + Caddy + Hetzner VPS 分享本地開發中的網站。自訂域名、自動 HTTPS、無限 tunnel。
替代方案(無 VPS 時):見
old-share-local-siteskill(ngrok/localhost.run)
使用此 skill 前,請將以下值替換成你自己的環境:
變數目前的值說明VPS IP5.223.75.160你的 VPS 公網 IP域名*.tunnel.fud.city你的 wildcard 子域名DNS ProviderCloudflare ( fud.city)管理你域名 DNS 的服務GitHub 備份https://github.com/darwin7381/frp-tunnel你的 private repo(可選)
Dashboard 密碼:不記在這裡。在 VPS 的
frps.toml裡設定你自己的密碼。
項目值VPS IP5.223.75.160VPS ProviderHetzner Cloud, Singapore, CPX12域名*.tunnel.fud.cityDNSCloudflare (fud.city)HTTPS 方式Wildcard cert (DNS-01 challenge via Cloudflare API)frp Dashboardhttp://5.223.75.160:7500GitHub 備份https://github.com/darwin7381/frp-tunnel (private)本地 config~/.frp/frpc.toml本地 tmux sessionfrpcVPS servicesfrps (systemd) + caddy (systemd)
名稱本地 PortURLnews-dashboard5173https://news.tunnel.fud.cityoldweb8080https://oldweb.tunnel.fud.cityapi8000https://api.tunnel.fud.cityfin-terminal5177https://terminal.tunnel.fud.cityfin-terminal-api3002https://terminal-api.tunnel.fud.city
VPS 上的 Caddy 有兩種方式為 tunnel 提供 HTTPS。 目前使用 Wildcard(推薦)。
原理:一張 *.tunnel.fud.city wildcard cert 涵蓋所有子域名。使用 DNS-01 challenge — Caddy 透過 Cloudflare API 自動加 TXT record 驗證。
Caddyfile:
caddyfile
*.tunnel.fud.city {
tls {
dns cloudflare {env.CF_API_TOKEN}
}
reverse_proxy localhost:8080
}
需要:
/etc/systemd/system/caddy.service.d/override.conf新增 tunnel 只需改本地 frpc.toml,不用動 VPS。
安裝步驟(已完成,僅供紀錄):
bash
# 1. 下載帶 cloudflare plugin 的 Caddy
curl -s "https://caddyserver.com/api/download?os=linux&arch=amd64&p=github.com%2Fcaddy-dns%2Fcloudflare" -o /usr/bin/caddy
chmod +x /usr/bin/caddy
# 2. 驗證 module 存在
caddy list-modules | grep cloudflare
# 3. 設定 CF token
mkdir -p /etc/systemd/system/caddy.service.d
cat > /etc/systemd/system/caddy.service.d/override.conf << EOF
[Service]
Environment="CF_API_TOKEN=你的token"
EOF
# 4. 更新 Caddyfile
cat > /etc/caddy/Caddyfile << EOF
*.tunnel.fud.city {
tls {
dns cloudflare {env.CF_API_TOKEN}
}
reverse_proxy localhost:8080
}
EOF
# 5. 重啟
systemctl daemon-reload
systemctl restart caddy
原理:每個子域名獨立簽一張 cert。使用 HTTP-01 challenge — Let's Encrypt 訪問 http://xxx/.well-known/acme-challenge/ 驗證。
Caddyfile:
caddyfile
news.tunnel.fud.city {
reverse_proxy localhost:8080
}
terminal.tunnel.fud.city {
reverse_proxy localhost:8080
}
# 每加一個 tunnel 就加一段
需要:標準版 Caddy 即可,不需要 API token。
缺點:每次加 tunnel 都要 SSH 進 VPS 改 Caddyfile 再 reload Caddy。
適合場景:
Wildcard → Per-Domain:
bash
ssh root@5.223.75.160
# 刪除 override.conf(或保留也無妨)
# 把 Caddyfile 改成逐一列出每個域名
systemctl restart caddy
Per-Domain → Wildcard: 按上面方式 A 的安裝步驟。
bash
SOCK=/tmp/openclaw-tmux/openclaw.sock
tmux -S $SOCK new-session -d -s frpc 'frpc -c ~/.frp/frpc.toml'
bash
SOCK=/tmp/openclaw-tmux/openclaw.sock
tmux -S $SOCK capture-pane -t frpc -p -S -10
Step 1 — 本地 config
編輯 ~/.frp/frpc.toml,加一段:
toml
[[proxies]]
name = "new-project"
type = "http"
localPort = 3000
customDomains = ["new.tunnel.fud.city"]
Step 2 — 重啟本地 frpc
bash
SOCK=/tmp/openclaw-tmux/openclaw.sock
tmux -S $SOCK send-keys -t frpc C-c
sleep 2
tmux -S $SOCK send-keys -t frpc 'frpc -c ~/.frp/frpc.toml' Enter
Step 3 — 驗證(不需要動 VPS!Wildcard cert 自動涵蓋)
bash
curl -sI https://new.tunnel.fud.city | head -5
確認回傳 HTTP/2 200 才告訴用戶。
Step 4 — 同步 GitHub 備份
bash
cd ~/Projects/frp-tunnel
cp ~/.frp/frpc.toml ./frpc.toml
git add -A && git commit -m "Add tunnel: new-project" && git push
同上 Step 1-2,但在 Step 2 和 3 之間多一步:
bash
ssh root@5.223.75.160
# 編輯 /etc/caddy/Caddyfile,加:
# new.tunnel.fud.city {
# reverse_proxy localhost:8080
# }
systemctl reload caddy
# 等 30 秒讓 cert 簽發
Vite dev server 預設會拒絕非 localhost 的 Host header。加 tunnel 時前端 vite.config.ts 也要加:
ts
server: {
allowedHosts: ['xxx.tunnel.fud.city'],
}
bash
frpc http --server-addr 5.223.75.160:7000 --local-port 3000 --custom-domain temp.tunnel.fud.city
Wildcard 模式下,臨時 tunnel 也自動有 HTTPS。
每次 發送 tunnel URL 給用戶前:
tmux capture-pane -t frpcstart proxy successcurl -s https://xxx.tunnel.fud.city | grep "<title>",title 必須是預期的網站名稱ps aux | grep <port> 檢查進程啟動時間,如果是幾天前啟動的舊進程,很可能已經僵屍化(佔 port 但不正常服務,偶爾回 200 但頁面空白)。殺掉重啟。curl --resolve 強制走 VPS IP,不要用已開過的 tab本地 dev server(如 Vite)長時間不重啟會變成僵屍:佔著 port、偶爾回 HTTP 200,但實際頁面是空白。 curl 檢查看似正常,瀏覽器有 cache 也看似正常,但外部用戶(包含手機)打開是空白。
排查步驟:
ps aux | grep <port> — 看進程啟動時間,超過 1-2 天就該懷疑npm run devbash
# SSH 進 VPS
ssh root@5.223.75.160
# 檢查 frps
systemctl status frps
journalctl -u frps --no-pager -n 20
# 檢查 Caddy
systemctl status caddy
journalctl -u caddy --no-pager -n 20
# 檢查 Caddy modules(確認有 cloudflare)
caddy list-modules | grep cloudflare
# 檢查 cert 狀態
caddy cert list 2>/dev/null || journalctl -u caddy | grep "certificate obtained"
# 重啟
systemctl restart frps
systemctl restart caddy
Port用途22SSH80HTTP (Caddy + Let's Encrypt)443HTTPS (Caddy)7000frp client 連線7500frp Web Dashboard