Lin.Log|Studio
// 01 · cloudflare-tunnel-self-hosted-wordpress$ cat cloudflare-tunnel-self-hosted-wordpress.md

家裡沒有公網 IP 但我把網站交給了雲

2026.05.07技術筆記5 分鐘閱讀
家裡沒有公網 IP 但我把網站交給了雲

技術主題:Cloudflare Tunnel + WordPress
實作時間:2026/04
工時估計:約 4 小時
紀錄者:_YLin_Lai
參考資料: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/

1.主題

本篇主題同詩意副標 — 家裡沒有公網 IP,但我把網站交給了雲。Cloudflare Tunnel 是一個讓自架 server 不用公網 IP、不用 port forwarding、也不用暴露真實 IP 的方案,適合我這種「家裡是中華電信動態 IP / 不想付靜態 IP 月費 / 不想被 DDoS 打到家用網路」的 freelancer。這篇是我把 IIS + WordPress 透過 Cloudflare Tunnel 上線到 ylinnlai.dpdns.org 的全紀錄。

2.背景(需求簡介)

自架站的第一個門檻不是技術,是網路。傳統做法是:跟 ISP 申請靜態公網 IP(中華電信光世代 NT$300+/月),家裡 router 開 port forwarding(80 + 443),DNS A record 指到那個 IP。三件事都各自有缺點 — 靜態 IP 要錢,port forwarding 暴露 server IP 給整個網際網路(被掃 port + 嘗試攻擊是日常),動態 DNS 在 IP 變動時還會有幾分鐘 downtime。

Cloudflare Tunnel 把這三件事一次解掉。它的核心想法是 outbound-only 連線 — server 不開 inbound port,而是主動連 Cloudflare 的全球邊緣節點,訪客打到 Cloudflare,Cloudflare 透過 tunnel 把 request 代理回家。家裡 server 在整個過程中對外沒有任何 inbound 暴露,連 IP 都不會被知道。

零基礎建設、零月費、順便接上 Cloudflare 的 DDoS 防護 + 全球 CDN + 自動 SSL,這個 deal 太划算了。

3.使用技術

cloudflared:Cloudflare 的 daemon,負責建立 outbound tunnel。Windows / Linux / macOS 都有版本,Windows 版可裝為 service 開機自動啟動,我用的就是 service 模式。

Cloudflare DNS:Cloudflare 自己的 DNS 託管服務。要把 dpdns.org 子網域委派給 Cloudflare,讓他們處理 DNS routing。

dpdns.org:免費的 dynamic DNS 服務,給沒有自有網域的人用。我的 ylinnlai.dpdns.org 就是從這裡申請的。

ingress YAML:tunnel 內的路由規則,告訴 cloudflared「打到 ylinnlai.dpdns.org 的 request,代理到 localhost:80」。

WP_HOME / WP_SITEURL:WordPress 內部 URL 設定。tunnel 接上後要強制 https,否則 WP 會生出 mixed content。

HTTP_CF_CONNECTING_IP:Cloudflare 在每個 request header 帶的真實訪客 IP。tunnel 接上後從 server log 看到的 IP 都是 CF 邊緣 IP,要靠這個 header 還原訪客真實 IP。

4.心得

整個 setup 大概 4 小時,其中 2 小時被 DNS 卡住,1 小時被 WordPress 的 IP 問題卡住,剩下 1 小時是才是在做事。

第一條:DNS 委派讓我頭大半天

dpdns.org 是個免費的 dynamic DNS 服務,但「免費」的代價是它的 DNS 介面非常陽春,不支援 CNAME flattening 等 Cloudflare Tunnel 需要的進階功能。Cloudflare 的解法是 — 把整個子網域 ylinnlai.dpdns.org 的 NS records 改指到 Cloudflare 的 nameservers:

XXXX.ns.cloudflare.com
XXXXXX.ns.cloudflare.com

實作上要去 dpdns.org 後台找到「NS records」設定(藏得很深,在 advanced 區),改完之後 dpdns.org 不再管這個子網域,DNS query 全部轉給 Cloudflare。

問題是 — DNS propagation。改完之後我用 nslookup 查,看到的 NS 還是 dpdns.org 的舊值。每隔 30 秒重整一次,連續半小時看到的都是舊值。我以為改錯了又改一次,改第三次時其實第一次就成功了,只是 propagation 沒這麼快。最終生效大概用了 40 分鐘。

DNS 不是即時的
它是分散式快取的妥協
你改完 別人不一定立刻知道

教訓:改 NS 之後給它 1 小時,不要重複改。

第二條:WordPress 看到的 IP 全部變 Cloudflare

Tunnel 接上後,我登入 wp-admin 看「最近登入」紀錄,看到的 IP 是 172.69.x.x — Cloudflare 邊緣節點的 IP。所有訪客留下的 IP 都是 Cloudflare 的,因為從 IIS 的角度看,request 確實是從 cloudflared daemon 過來的,它就是 Cloudflare。

這對 anti-spam plugin / 登入安全 plugin 是災難 — 它們會看到「同一個 IP 在 1 分鐘內登入了 100 次」,因為所有訪客在它們眼裡都長一樣。

解法是在 wp-config.php 加上 Cloudflare 真實 IP 還原:

if ( !empty( $_SERVER['HTTP_CF_CONNECTING_IP'] ) ) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
}

這幾行的意思是 — 如果 request header 裡有 Cloudflare 帶的 CF-Connecting-IP,就用它覆蓋 PHP 看到的 REMOTE_ADDR。覆蓋之後,WordPress / plugin / log 看到的就是訪客真實 IP。

網路上沒有秘密
但你可以選擇
讓哪一層先看到你

順便講一下 SSL — Cloudflare 會在 edge 自動發 universal SSL,所以訪客到 Cloudflare 那一段是 https。但 cloudflared 到 IIS 那一段預設是 http(localhost:80),整體還是 https,因為 IIS 本身在私有網路內,沒有暴露給外界。SSL 模式在 Cloudflare dashboard 選「Full」就好,不用「Strict」(Strict 會要求 IIS 那邊也有 valid cert,localhost 沒有真 cert 會掛)。

結語:

「家裡沒有公網 IP 但我把網站交給了雲」這句副標講的不只是省了 NT$300/月的靜態 IP 費 — 而是把家用網路的所有暴露面 全部關掉。家裡 router 不用開 port、server IP 不會被掃、DDoS 在 Cloudflare 邊緣就被擋。所有對外的接觸,都先經過 Cloudflare 那層信任邊界。

對工程師讀者:cloudflared 的 config.yml + WP_HOME 強制 https + CF-Connecting-IP 三步驟,是任何自架 WP / 自架 service 都該做的基本盤。對客戶讀者 — 不用買固定 IP、不用開 router port、自帶 SSL + DDoS 防護,我能幫你架。

相關紀錄

彩蛋:Tunnel 拓樸圖

                    訪客(任何位置)
                          ↓ HTTPS 443
                ┌──────────────────────────┐
                │ Cloudflare Edge (全球 CDN) │
                │  ylinnlai.dpdns.org       │
                └──────────────────────────┘
                          ↓ outbound tunnel
                  ┌──────────────────┐
                  │   cloudflared    │
                  │ (家裡 Windows    │
                  │  Server 跑 svc)  │
                  └──────────────────┘
                          ↓ http://localhost:80
                  ┌──────────────────┐
                  │  IIS + WordPress │
                  └──────────────────┘

整條鏈上,家裡 router 沒開任何 inbound port。 這就是 Cloudflare Tunnel 在做的事。

不說了 去看自己網站 真的活著! ٩(。・ω・。)و

linlog@studio $ exit

有東西想一起做出來?

[聯繫我]
email dannylaii@linlogstudio.com
hours Mon – Fri · After 7PM
base Taiwan · 遠端優先
Connection to lin.log closed. © 2026 Lin.Log|Studio