跳到內容
開源

加上公開網域與 HTTPS

將網域接到服務,設定 HTTPS 憑證、轉址與訪客密碼。

在服務 網路 的 公開網域 按 新增網域,輸入網域並加入變更,檢查後套用,再到 DNS 供應商新增畫面列出的紀錄。網址能連到服務且 HTTPS 憑證就緒後,訪客就能開啟網站。

  • 服務有接收 HTTP 流量的連接埠,而且 私有網路 看得到它的私有位址。網域會把請求轉送到這個位址。沒有的話,先照畫面上的說明開放連接埠。
  • 擁有網域的 DNS 管理權限,或有人能代為修改 DNS。
  • 有權修改專案的網域。如果路由由 Helm、Argo CD 或 Flux 管理,要回到原本的 values 或 Git 儲存庫修改。
  • 叢集裝了 cert-manager 和可用的簽發者,憑證才會自動簽發、更新。萬用字元網域(例如 *.example.com)要用支援 DNS-01 的簽發者。

進入服務 網路,在 公開網域 按 新增網域,輸入 app.example.com。欄位只填主機名稱,不加 https://、連接埠或路徑。

叢集有多個簽發者時,表單會出現 簽發者,可以保留預設或改選另一個。如果這個網域拿不到憑證,檢查變更時會提示它只有 HTTP。

叢集有 Gateway 接受這個專案的路由時,表單會多一個 路由,預設是 Ingress(預設),也可以選某個 Gateway 的 listener,網域就會用 HTTPRoute 掛在那個 Gateway 上。選了 Gateway 就不會出現簽發者,HTTPS 憑證由 listener 提供。只有能讀取叢集 Gateway 的帳號看得到這個選項,看不到時請叢集管理員幫忙。

按 加入變更,網域會先放進這個服務的草稿,叢集還沒有改動。從頁面下方按 檢查變更,確認網域、轉送目標和憑證設定後套用。

表單沒有連接埠欄位,所以要在檢查時看 轉送到 的服務和連接埠。服務已經有 Ingress 時,新網域加在同一個 Ingress 上,沿用它的後端。只有 HTTPRoute 時,新網域加在那條 HTTPRoute 上。都沒有時,Zeabur 建立新的 Ingress,轉送到服務第一個 Kubernetes Service 的第一個連接埠。選了 Gateway 時,新網域加在那個 Gateway 上轉送到這個服務的 HTTPRoute,沒有就建一條新的。

到 DNS 供應商新增畫面列出的紀錄,照抄類型、名稱和值:

  • 目標是 IPv4 位址時,使用 A。
  • 目標是 IPv6 位址時,使用 AAAA。
  • 目標是另一個主機名稱時,使用 CNAME。

如果網域在叢集的應用程式網域底下,例如 shop.apps.example.com,畫面會改成請管理員新增萬用字元紀錄 *.apps.example.com。已經有這筆紀錄,就不用另外設定。Zeabur 不會替你修改 DNS。

畫面顯示 Zeabur 不知道叢集的入口位址,請問管理員要指向哪個位址 時,先向叢集管理員要入口的對外位址,再設定 DNS。

回到 公開網域 查看 DNS 和憑證狀態。DNS 還沒指向叢集或憑證還在簽發時,網域列會寫出下一步。簽發失敗時,展開 cert-manager 的訊息 看原因,cert-manager 也會自己重試。

狀態變成 設定正確 後,從瀏覽器開啟網址,確認看到的是這個服務、瀏覽器沒有憑證警告。如果應用程式會產生完整網址,再到環境變數更新 APP_URL 這類設定。

憑證、轉址和密碼、維護與錯誤頁面這三個側邊面板,最後一個按鈕都是 加入變更。變更會和新增、改名的網域放在同一份草稿,網域列標上 已修改,旁邊有 復原。全部改好後,從頁面下方按 檢查變更,確認後一起套用。只有一種變更時,按鈕寫出那個動作(例如 新增網域),混合多種時寫 套用 N 項變更。

同一個設定改兩次,後一次會取代前一次,草稿裡只留最後的版本。

專案還沒有頁面伺服器時,維護與錯誤頁面的變更會帶著部署 Error pages 範本的一項,和其他變更一起檢查、套用。

在網域列按 app.example.com 的憑證,開啟側邊面板。

選 由簽發者簽發,自動更新,指定 簽發者,按 加入變更。同一個 Ingress 的網域共用一個簽發者,所以改了以後,面板列出的其他網域也會改由這個簽發者簽發。

萬用字元網域顯示需要 DNS-01 時,請叢集管理員照下一節建立簽發者,再回到網域選它。

Let's Encrypt 只支援透過 DNS-01 驗證簽發萬用字元憑證。叢集管理員需要用 kubectl 建立 DNS-01 簽發者,讓 cert-manager 的 DNS-01 solver 使用 DNS 供應商的 API token 完成驗證。Token 只放在叢集裡的 Secret,Zeabur 不經手;叢集 → 概覽 的 憑證 只列出簽發者和狀態,不能新增。

以下以 Cloudflare 為例。先建立 API token,將 DNS 編輯權限限制在要使用的那個 zone,再把下方的佔位符換成你的 token:

kubectl -n cert-manager create secret generic cloudflare-dns \
--from-literal=api-token='<只能編輯這個 zone 的 token>'

Secret 必須放在 cert-manager namespace。ClusterIssuer 只會讀取 cert-manager 設定的 cluster resource namespace 裡的 Secret;這裡使用的是 cert-manager。

接著建立 letsencrypt-dns 簽發者。請將 you@example.com 換成你的聯絡信箱:

kubectl apply -f - <<'EOF'
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-dns
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: you@example.com
privateKeySecretRef:
name: letsencrypt-dns-account-key
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-dns
key: api-token
EOF

建立後,確認簽發者的狀態:

kubectl get clusterissuer letsencrypt-dns

等 READY 顯示 True,回到 Zeabur 的叢集 → 概覽 的 憑證,就會看到 letsencrypt-dns 和它的就緒狀態。設定萬用字元網域時,在 簽發者 選擇 letsencrypt-dns。

如果使用 Route 53、Cloud DNS、DigitalOcean 或 Azure DNS 等其他供應商,請換成對應的 solver,並依照 cert-manager 的 DNS-01 文件設定憑證與權限。

選 我自己的憑證,貼上或按 上傳檔案 提供:

  • 憑證(PEM):先放網站憑證,再放中繼憑證。
  • 私密金鑰(PEM):提供未加密、與憑證配對的私密金鑰。

按 加入變更,再從頁面下方檢查並套用。Zeabur 會檢查憑證的有效日期、網域名稱和金鑰是否配對,再把憑證和金鑰存進 Secret,之後不會再顯示金鑰。自己的憑證不會自動更新,要在到期前上傳新的。

同一個 Ingress 的其他網域還在向 cert-manager 申請憑證時,這個網域會移到自己的 Ingress。新的 Ingress 沿用原本的規則、class、標籤、註解和錯誤頁面,檢查變更時會列出這次搬移。原本的 Ingress 設了密碼、轉址或維護模式時不能搬,面板會寫出要先取消哪一項。

網域由 HTTPRoute 提供時,憑證設定在叢集的 Gateway 上,網域列顯示 HTTPS 由 Gateway 決定。要換憑證,請叢集管理員到 Gateway 更改。

轉址出現在由 Traefik 提供的 Ingress,以及 HTTPRoute 上。在來源網域列按 app.example.com 的轉址或密碼,選 轉到另一個網域,輸入 要轉到的網域。

只填目標主機名稱,例如 www.example.com。轉址後使用 HTTPS,路徑保留,app.example.com/docs 會轉到 https://www.example.com/docs。目標網域要先有自己的 DNS、路由與可用憑證。

轉址類型 可選 暫時(302) 或 永久(301)。瀏覽器會記住永久轉址,之後取消也會繼續轉,所以先用暫時轉址確認目標。

按 加入變更,從頁面下方檢查並套用,再開啟來源網域測試。轉址只對這個網域生效,同一個 Ingress 的其他網域照樣顯示原服務。萬用字元網域不能當轉址的來源或目標。

HTTPRoute 的轉址作用在整條路由。同一條 HTTPRoute 還有其他網域時,這個網域會移到自己的路由,其他網域留在原處。Zeabur 在路由最前面加一條轉址規則,比對原本所有規則的路徑;原本的規則留著不動,取消轉址時只拿掉這一條。

要取消轉址,在同一個面板改選 顯示 web(web 是服務名稱),再加入變更並套用。

在網域列按 app.example.com 的轉址或密碼,開啟 要求輸入密碼,填入 使用者名稱 與 密碼。使用者名稱不能有空格或冒號,密碼至少 8 個字元,最多 72 個位元組。密碼只能設在 Traefik 提供的 Ingress 上,HTTPRoute 的網域目前無法在這裡設定密碼。

密碼設在整個 Ingress 上。面板列出 www.example.com 這類共用同一個 Ingress 的網域時,它們也會要求同一組帳號密碼。加入變更、檢查並套用後,用無痕視窗開啟網址,確認會跳出密碼提示,輸入後能看到服務。

叢集只保存密碼的 bcrypt 雜湊值,忘記密碼時只能換一組。已有密碼時按 變更 換帳號密碼。關閉 要求輸入密碼 再套用,就會拿掉這個 Ingress 的密碼。

轉址排在密碼前面。來源網域同時設了轉址,訪客不用輸入密碼就會直接轉到目標。目標要密碼保護,就在目標網域自己的面板設定。

  • 改名:按網域列的編輯按鈕,輸入新名稱,按 加入變更,再從頁面下方檢查並套用。接著設定新網域的 DNS。如果用的是自己上傳的憑證,要換一份涵蓋新名稱的憑證。
  • 移除其中一個網域:按該列的移除按鈕,從頁面下方檢查並套用,再到 DNS 供應商刪除不再使用的紀錄。
  • 移除路由的最後一個網域:移除按鈕會寫出連同哪條路由一起移除,例如 移除 app.example.com,連同沒有其他網域的路由 web。檢查變更時會列出要刪除的 Ingress 或 HTTPRoute。

還沒套用的網域變更,可以在該列按 復原,或按頁面下方 捨棄 放棄整份草稿。側邊面板按 加入變更 之前關掉,就不會留下任何變更。

網域、憑證、轉址和密碼都是一般的 Ingress、HTTPRoute、Secret 和 Traefik Middleware。Zeabur 沒有自己的 CRD 或控制器,移除 Zeabur 之後,網站照樣由 Traefik 和 cert-manager 提供。以下以專案 demo、服務 web(Service 連接埠 8080)、網域 app.example.com 為例。

服務還沒有路由時,Zeabur 建立名為 <服務>-<網域,點換成破折號> 的 Ingress。cert-manager 依 annotation 簽發憑證,存到 <Ingress 名稱>-tls:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-app-example-com
namespace: demo
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
tls:
- hosts: [app.example.com]
secretName: web-app-example-com-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 8080

letsencrypt 換成叢集裡簽發者的名稱,用 kubectl get clusterissuer 查。服務已經有 Ingress 時,Zeabur 會把新網域加成同一個 Ingress 的另一條 rules,並在 tls 加一筆。

選了 Gateway 的網域是一條 HTTPRoute,parentRefs 指向 Gateway 和它的 listener:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web-app-example-com
namespace: demo
spec:
parentRefs:
- name: public
namespace: gateway
sectionName: https
hostnames: [app.example.com]
rules:
- backendRefs:
- name: web
port: 8080

自己的憑證是一個 kubernetes.io/tls Secret,Ingress 的 tls.secretName 指向它。Zeabur 建立的 Secret 名稱是 <Ingress 名稱>-cert,ownerReferences 指向 Ingress。Ingress 只有這個網域時,用 kubectl 建立 Secret,再把 Ingress 改成讀它,並拿掉 cert-manager 的 annotation:

kubectl -n demo create secret tls web-app-example-com-cert --cert=fullchain.pem --key=privkey.pem
kubectl -n demo patch ingress web-app-example-com --type=json -p='[{"op":"replace","path":"/spec/tls/0/secretName","value":"web-app-example-com-cert"}]'
kubectl -n demo annotate ingress web-app-example-com cert-manager.io/cluster-issuer-
kubectl -n demo delete certificate web-app-example-com-tls

最後一行刪掉 cert-manager 之前為這個網域建立的 Certificate,Zeabur 換成自己的憑證時也會這樣做。

轉址和密碼是 Traefik 的 Middleware,ownerReferences 指向 Ingress,刪掉 Ingress 時一起刪除。Ingress 的 annotation traefik.ingress.kubernetes.io/router.middlewares 依序列出它們,格式是 <專案>-<Middleware 名稱>@kubernetescrd,以逗號分隔。轉址排第一個,密碼排最後一個。

轉址的名稱是 <Ingress 名稱>-redirect-<來源網域,點換成破折號>,只比對來源網域,保留路徑。permanent: true 是 301,false 是 302:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: web-app-example-com-redirect-app-example-com
namespace: demo
spec:
redirectRegex:
regex: ^https?://app\.example\.com(:[0-9]+)?/(.*)
replacement: https://www.example.com/${2}
permanent: false

密碼的 Secret 和 Middleware 都叫 <Ingress 名稱>-basic-auth。Secret 的 users 是一行 htpasswd,密碼用 bcrypt 雜湊。用 htpasswd -nbB 產生這一行:

kubectl -n demo create secret generic web-app-example-com-basic-auth \
--from-literal=users="$(htpasswd -nbB ops '換成你的密碼')"
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: web-app-example-com-basic-auth
namespace: demo
spec:
basicAuth:
secret: web-app-example-com-basic-auth
removeHeader: true

最後把兩個 Middleware 寫進 Ingress 的 annotation,轉址在前:

kubectl -n demo annotate ingress web-app-example-com --overwrite \
traefik.ingress.kubernetes.io/router.middlewares=demo-web-app-example-com-redirect-app-example-com@kubernetescrd,demo-web-app-example-com-basic-auth@kubernetescrd

要取消轉址或密碼,先從 annotation 拿掉那一項,再刪 Middleware(和密碼的 Secret)。順序相反的話,Traefik 找不到 Middleware,網域會回 404。

Ingress 只剩這個網域時,刪掉整個 Ingress。它擁有的 Middleware、維護 Ingress 和自己上傳的憑證 Secret 會一起刪除:

kubectl -n demo delete ingress web-app-example-com

Ingress 還有其他網域時,用 kubectl edit 只拿掉這個網域的 rules 和 tls.hosts。

在服務 網路 的 公開網域,網域列會寫出 DNS 和憑證狀態,以及 轉送到 的服務和連接埠。設了轉址或密碼的網域,旁邊的按鈕會顯示目前的設定。

用 kubectl 看路由和憑證:

kubectl -n demo get ingress
kubectl -n demo get certificate
kubectl -n demo get middleware.traefik.io

kubectl get ingress 的 HOSTS 欄有這個網域,ADDRESS 欄是入口的對外位址。kubectl get certificate 的 READY 是 True,表示 cert-manager 已經簽好憑證。最後從叢集外確認:

curl -sI https://app.example.com/

回應的狀態碼是服務自己的回應(例如 200)。設了轉址時是 301 或 302,location 指向目標網域。設了密碼時是 401。

畫面或結果接著處理
沒有 新增網域先看 私有網路 有沒有私有位址,再確認你有修改網域的權限。
指向別處核對 DNS 紀錄和畫面列出的目標。前面有 CDN 或代理時也會顯示這個狀態,這時要確認 CDN 的來源指到叢集。
DNS 正確,憑證一直在簽發或 憑證簽發失敗展開 cert-manager 的訊息,核對簽發者,以及驗證要用的 DNS 紀錄或入口設定。
沒有轉址或密碼按鈕網域由 Traefik 以外的 Ingress controller 提供,要在它自己的設定處理。
狀態 尚未確認,或瀏覽器連不上依序核對 DNS、入口位址、服務是否就緒和連線規則。Zeabur 從叢集裡檢查,結果可能和你的瀏覽器不同。

要暫時擋住訪客、保留網域和服務,用維護模式。