# 🔐 HTTPS 📌 下方 TLS 範例使用目前工作目錄的 `./certs/`;請放入自己的憑證、配對金鑰或用戶端 CA 檔案。驗證也會讀取這些檔案。 位址是公開網域名稱的網站區塊,不寫 `tls` 指令也會有 HTTPS:Pingclair 會透過 ACME 向 Let's Encrypt 申請憑證,在 80 連接埠回應 HTTP-01 驗證,把結果存起來,並在背景自動續期。另外三種取得憑證的方式——DNS-01、本機憑證授權單位,以及你自己提供的檔案——在下面分別說明,連同各自的前提條件。 ## 🧾 開始之前 - 一個解析到這台主機的網域名稱。怪罪伺服器之前先檢查一下:`dig +short A example.com`。 - 80 與 443 連接埠能從網際網路連到。HTTP-01 驗證在 80 連接埠上提供,憑證則用在 443。 - ACME 帳號用的 email 地址。它必須是真實的信箱:Let's Encrypt 會拒絕保留的範例網域,簽發會以 `contact email has forbidden domain "example.com"` 失敗。 下面的設定會取代服務執行的 `/etc/Pingclair/Pingclairfile`。重載前請先驗證;[快速開始](/zh-TW/start/quickstart/)示範了這個流程,[以服務方式執行](/zh-TW/start/service/)則說明重載。 ## 🌐 來自 Let's Encrypt 的憑證 ```caddyfile { email bonjour@pingclair.com } example.com { file_server /var/lib/pingclair/html } ``` 不需要其他設定。啟動時,伺服器會授權這個主機名稱、啟動 ACME 流程,並提供驗證回應: ```text 🌐 Automatic public certificates authorised for 1 hostname(s) 🚀 Eager issuance for 1 hostname(s) 🔐 Starting ACME flow for domains: ["example.com"] 🔐 Serving ACME challenge for token: Ix9X74-tENLdJY0F6f7kUe3TXkoXOxOyTb8iHcnv9Z4 ✅ Certificate stored successfully: example.com 🎉 Certificate issuance complete for example.com ``` 存取日誌中的驗證請求來自憑證授權單位,而不是瀏覽器: ```text 📝 Access ... path="/.well-known/acme-challenge/Ix9X74-..." status=200 user_agent="Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)" ``` 從另一台機器確認實際提供的內容: ```bash curl -I https://example.com/ ``` ```text HTTP/2 200 content-type: text/html; charset=utf-8 etag: "493b-6ab1f452" server: Pingclair ``` ```bash echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \ | openssl x509 -noout -subject -issuer -dates ``` ```text subject=CN=example.com issuer=C=US, O=Let's Encrypt, CN=YE2 notBefore=Sep 22 02:35:03 2026 GMT notAfter=Dec 21 02:35:02 2026 GMT ``` 憑證資料保存在服務使用者的資料目錄 `/var/lib/pingclair/.local/share/pingclair`——這是二進位檔從該帳號的家目錄推算出的路徑,也是以其他使用者身分執行命令時,`PINGCLAIR_TLS_STORE` 要指定的路徑。 ## 📡 DNS-01 與萬用字元憑證 DNS-01 以發布一筆 TXT 記錄來證明你掌控某個名稱,而不是在 80 連接埠上回應。萬用字元憑證必須用它,80 連接埠關閉的主機也一樣。 📌 **DNS-01 支援 Cloudflare,其他 provider 名稱會被拒絕。** 伺服器發布 ACME TXT 摘要,並保留同名的其他 TXT 記錄。 設定需要 provider 區塊: ```caddyfile { email bonjour@pingclair.com } *.example.com { tls { auto dns cloudflare resolvers 1.1.1.1 propagation_delay 10s } file_server /var/lib/pingclair/html } ``` 有兩個細節容易漏掉。第一,區塊裡的 `auto` 這一行才會把名稱放進簽發清單;少了它,伺服器會記錄 `authorised for 0 hostname(s)`,永遠不會申請憑證,每次交握都會以 `NO_CERTIFICATE_SET` 失敗。第二,token 是 Cloudflare API token,必須對存放該名稱的 zone 具有 `Zone:DNS:Edit` 權限。 🃏 **一張葉憑證涵蓋整個網站。** `*.example.com` 網站申請的就是 `*.example.com` 本身:一張在啟動時取得的憑證,提供給它底下的每一個名稱。萬用字元只涵蓋恰好一層標籤,所以頂層網域需要自己的項目——如果網站也要回應 `example.com`,請寫成 `*.example.com, example.com`,每個主體都會照書寫的樣子申請。以這種方式提供的子網域不會出現在 Certificate Transparency 日誌中,這本來就是使用萬用字元的隱私理由。 網站底下的任何名稱都由這一張葉憑證提供。從另一台機器: ```bash curl -I https://anything.example.com/ ``` ```text HTTP/2 200 content-type: text/html; charset=utf-8 server: Pingclair ``` ```bash echo | openssl s_client -connect example.com:443 -servername anything.example.com 2>/dev/null \ | openssl x509 -noout -subject -issuer -ext subjectAltName ``` ```text subject=CN=*.example.com issuer=C=US, O=Let's Encrypt, CN=YE1 X509v3 Subject Alternative Name: DNS:*.example.com ``` ## 🏛️ 來自內部憑證授權單位的憑證 對於私有的源站——tunnel、內部主機名稱、實驗用的機器——Pingclair 可以自己當憑證授權單位: ```caddyfile https://internal.test { tls internal file_server /var/lib/pingclair/html } ``` 內部憑證授權單位包含根憑證與簽發 90 天葉憑證的中繼憑證。根憑證位於 `/pki/authorities/local/root.crt`。 用戶端目前還不信任它,所以不加 `-k` 的請求會失敗。把根憑證安裝到系統的信任儲存區: ```bash sudo PINGCLAIR_TLS_STORE=/var/lib/pingclair/.local/share/pingclair pingclair trust ``` ```text ✅ Internal CA root installed into the system trust store ``` `PINGCLAIR_TLS_STORE` 前綴很重要:`pingclair trust` 會去找執行它的使用者的儲存區,對 root 而言是 `/root/.local/share/pingclair`,但服務用的是 `/var/lib/pingclair/.local/share/pingclair`。少了這個前綴就會查找 root 自己的儲存區,無法找到服務的根憑證。 信任根憑證之後,同一個請求不加 `-k` 也會成功: ```bash curl -s -o /dev/null -w '%{http_code}\n' https://internal.test/ ``` ```text 200 ``` `pingclair untrust` 可以再把它移除,同樣要加上儲存區前綴。 📌 **升級注意。** 舊的 `internal/` 目錄不會遷移;0.2.0 會建立新的憑證授權單位。每個用戶端都必須重新信任根憑證。 ## 📜 你自己提供的憑證 當憑證由其他系統簽發時,把 `tls` 指向那些檔案: ```caddyfile https://byo.test { tls { cert ./certs/byo.crt key ./certs/byo.key } file_server /var/lib/pingclair/html } ``` 這些檔案必須讓 `pingclair` 使用者讀得到,因為服務是以該使用者身分執行的。`validate` 會讀取並解析憑證與金鑰,檢查兩者配對,不開啟監聽器。不存在的路徑會直接被拒絕: ```text ❌ TLS certificate file does not exist: /etc/pingclair/certs/missing.crt ``` ## ⚠️ HTTPS 無法啟用時 - **`contact email has forbidden domain "example.com"`。** Let's Encrypt 不接受保留的範例網域作為帳號聯絡人。請在 `email` 選項裡填入真實的信箱。 - **日誌中出現 `NO_CERTIFICATE_SET`。** 交握時提出的名稱,伺服器沒有對應的憑證。請看它上方的日誌:沒有 `auto` 的 `tls` 區塊永遠不會開始簽發,並確認 DNS challenge 設定。 - **驗證回應從未被提供。** 80 連接埠被防火牆擋住,或被其他程式佔用。憑證授權單位必須能從網際網路連到 `http://your-name/.well-known/acme-challenge/`。 - **名稱沒有解析到這台主機。** `dig +short A your-name` 會顯示憑證授權單位將連到哪裡,剛改過設定時,結果不一定是你預期的。 - **反覆失敗。** Let's Encrypt 會依主機名稱限制驗證失敗的次數。重試前先修好原因,否則重試本身就會變成錯誤。 ## 🧭 下一步 - [以服務方式執行](/zh-TW/start/service/):unit、它的重載語意,以及它的日誌。 - [`tls`](/zh-TW/reference/directives/#tls):這個指令的每種模式與選項。 - [Pingclairfile](/zh-TW/reference/pingclairfile/):位址、匹配器,以及編譯器接受什麼。