告別 localhost:3000 — 反向代理完全上手指南

告別 localhost:3000 — 反向代理完全上手指南

reverse-proxy-cover

localhost:3000 是前端、localhost:8080 是 API、localhost:5432 是資料庫管理介面、localhost:9000 是另一個微服務... 我甚至得開一個備忘錄記錄哪個 port 是什麼服務,不然隔天醒來完全想不起來。

更慘的是,當我想測試一個需要 HTTPS 的功能時,瀏覽器跳出那個刺眼的「您的連線不安全」警告,點了好幾次「繼續前往」才能看到畫面。這種開發體驗,說實話,真的很差。


反向代理:你的網站需要一個「前台」

怎麼說呢,你可以把反向代理想像成公司的前台。

想像一下:如果一間公司沒有前台,訪客直接闖進辦公區找人會發生什麼事?有人找工程部、有人找業務部、有人其實是來推銷的、有人根本走錯棟...整個辦公室會亂成一團。

所以公司會設一個前台。訪客先到前台,說明來意,前台確認身份後再引導到正確的部門。推銷員?直接擋掉。可疑人物?通報保全。

reverse-proxy-comparison

反向代理做的就是這件事,只是場景換成了網路世界。

所有來自網路的請求,不會直接打到你的後端伺服器,而是先經過反向代理這個「前台」。反向代理會檢查請求、決定要轉發給哪個服務、處理一些雜事(像是 SSL 加解密),然後把回應送回給使用者。

你的後端服務們呢?它們只需要專心做自己的事,不用煩惱外面的世界有多混亂。

正向 vs 反向,三秒區分

這兩個詞很容易搞混,我用一個簡單的方式區分:

正向代理:幫「你」出去拿東西。你不想讓外面知道你是誰,所以派一個代理人出去。VPN 就是這個概念。

反向代理:幫「伺服器」接待客人。外面的人不知道裡面有幾台伺服器、長什麼樣子,只看到一個統一的入口。

一句話記住:正向保護客戶端,反向保護伺服器。


它能幫你做什麼?

好,概念懂了,但反向代理到底能解決什麼問題?

統一入口,告別 port 地獄

這是我當初最有感的一點。有了反向代理,你可以這樣設定:

  • myapp.local → 前端服務
  • api.myapp.local → API 服務
  • admin.myapp.local → 管理後台

全部走 443 port,全部用漂亮的網址,再也不用記那些該死的 port 號。

自動 HTTPS,一勞永逸

現在很多功能都需要 HTTPS 才能用:地理定位、相機存取、Service Worker... 在本地開發環境搞 HTTPS 以前是件很痛苦的事,要自己生憑證、設定信任、每次都要點「繼續前往不安全的網站」。

但有些反向代理工具(像 Caddy)可以自動幫你處理 SSL 憑證。在生產環境它會自動向 Let's Encrypt 申請免費憑證,在本地開發則可以搭配 mkcert 產生被系統信任的憑證。

負載均衡

當你的服務開始有流量,一台伺服器撐不住的時候,反向代理可以幫你把請求分散到多台伺服器。這就是所謂的負載均衡。

                    ┌─ Server 1
使用者 → 反向代理 ──┼─ Server 2
                    └─ Server 3

反向代理會用各種演算法(輪詢、最少連線、IP Hash)來決定要把請求送到哪台伺服器。

安全防護

因為外部請求不會直接接觸到後端伺服器,所以:

  • 後端伺服器的真實 IP 被隱藏
  • 可以在反向代理層做速率限制,擋掉惡意請求
  • 可以設定 WAF(Web Application Firewall)過濾攻擊
  • DDoS 攻擊打到的是反向代理,不是你的應用伺服器

快取加速

反向代理可以快取靜態資源(圖片、CSS、JS),這樣重複的請求就不用每次都打到後端,大幅減少伺服器負擔。


四大天王,怎麼選?

reverse-proxy-software

市面上反向代理的選擇很多,但最常被拿出來討論的就是這四個:Nginx、Caddy、Traefik、HAProxy。

我花了不少時間研究和實測,簡單分享一下心得。

Nginx:穩如老狗的老將

Nginx 大概是最多人用的反向代理,從 2004 年就存在了。效能極強、資源消耗低、文件和社群資源超級豐富。

但說實話,它的設定檔對新手不太友善。光是要設定一個基本的反向代理,就要寫這麼一大段:

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

如果你追求極致效能、需要非常細緻的控制,或是你已經很熟悉 Nginx,那它絕對是好選擇。

Caddy:簡單到不可思議的新星

Caddy 是這幾年竄起來的新選擇,主打「簡單」和「自動 HTTPS」。

同樣的功能,Caddy 的設定長這樣:

example.com {
    reverse_proxy localhost:3000
}

沒了。就這三行。

HTTPS 憑證?它會自動幫你處理。HTTP 轉 HTTPS?預設就會。

我第一次用 Caddy 的時候真的有點驚訝,怎麼可以這麼簡單?效能雖然比 Nginx 稍微差一點,但對大多數應用來說根本感覺不出來。

如果你是新手,或是你只是想快速把事情搞定,Caddy 是我最推薦的選擇。

Traefik:為容器而生

如果你的服務都跑在 Docker 或 Kubernetes 上,Traefik 會讓你很驚豔。

它可以自動偵測 Docker 容器的啟動和關閉,不用手動改設定檔。你只要在 docker-compose.yml 裡加幾個 label,Traefik 就會自動幫你設定好路由。

services:
  myapp:
    image: myapp
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.myapp.rule=Host(`myapp.local`)"

缺點是學習曲線比較陡,概念也比較多(providers、routers、middlewares...),效能也是四個裡面最差的。但在容器環境裡,那個自動化的體驗真的很香。

HAProxy:負載均衡之王

HAProxy 專注在負載均衡這件事上,做到極致。很多大公司的高流量系統都用它。

但它不是 web server,沒有內建快取功能,設定也相對複雜。如果你的場景主要是「把流量分散到很多台伺服器」,HAProxy 是專業選擇。一般使用的話,Nginx 或 Caddy 就夠了。

所以到底怎麼選?

你的情況 推薦
新手、想快速上手 Caddy
追求極致效能 Nginx
Docker/Kubernetes 環境 Traefik
大規模負載均衡 HAProxy
不知道選什麼 Caddy

動手做:5 分鐘搞定本地開發環境

說了這麼多,來實際操作一下。我會用最簡單的方式,讓你在本地開發環境用上 HTTPS 和自訂域名。

第一步:安裝 mkcert

mkcert 是一個工具,可以產生被本機系統信任的 SSL 憑證。

# macOS
brew install mkcert nss

# 安裝本地 CA(只需要執行一次)
mkcert -install

第二步:產生憑證

# 在你的專案目錄下
mkdir certs && cd certs
mkcert myapp.local "*.myapp.local"

這會產生兩個檔案:myapp.local+1.pem(憑證)和 myapp.local+1-key.pem(私鑰)。

第三步:設定 hosts 檔案

# 編輯 /etc/hosts(需要 sudo)
sudo nano /etc/hosts

# 加入這行
127.0.0.1 myapp.local api.myapp.local

第四步:建立 Caddyfile

myapp.local {
    tls ./certs/myapp.local+1.pem ./certs/myapp.local+1-key.pem
    reverse_proxy localhost:3000
}

api.myapp.local {
    tls ./certs/myapp.local+1.pem ./certs/myapp.local+1-key.pem
    reverse_proxy localhost:8080
}

第五步:啟動 Caddy

# 安裝 Caddy(如果還沒裝)
brew install caddy

# 啟動
caddy run

完成。現在打開瀏覽器,輸入 https://myapp.local,你會看到漂亮的綠色鎖頭,連到你的前端服務。

如果你用 Docker Compose,可以把 Caddy 也容器化,整個開發環境一個 docker-compose up 就搞定。


下一步

反向代理這個概念其實不複雜,但它能解決的問題比你想像的多。

從今天開始,試著在你的下一個專案用上它。不一定要用在生產環境,光是本地開發就能讓你的體驗好上很多。

當你開始習慣 https://myapp.local 這種開發方式,你就回不去了。

至於更進階的主題——雲端部署、安全配置、Kubernetes Ingress——那就是另一個故事了。

先把基礎打好,其他的慢慢來。


延伸閱讀


如果這篇文章對你有幫助,歡迎分享給同樣在跟 port 地獄奮戰的朋友。


本文最初發布於 HackMD @BASHCAT

留言

這個網誌中的熱門文章

Arduino 課本可能沒教的事(1)

SI4432 搭配Arduino

燒錄 Arduino mini Pro 燒錄