跳到內容

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。重載前請先驗證;快速開始示範了這個流程,以服務方式執行則說明重載。

{
email bonjour@pingclair.com
}
example.com {
file_server /var/lib/pingclair/html
}

不需要其他設定。啟動時,伺服器會授權這個主機名稱、啟動 ACME 流程,並提供驗證回應:

🌐 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

存取日誌中的驗證請求來自憑證授權單位,而不是瀏覽器:

📝 Access ... path="/.well-known/acme-challenge/Ix9X74-..." status=200 user_agent="Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"

從另一台機器確認實際提供的內容:

終端機視窗
curl -I https://example.com/
HTTP/2 200
content-type: text/html; charset=utf-8
etag: "493b-6ab1f452"
server: Pingclair
終端機視窗
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
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 以發布一筆 TXT 記錄來證明你掌控某個名稱,而不是在 80 連接埠上回應。萬用字元憑證必須用它,80 連接埠關閉的主機也一樣。

📌 DNS-01 支援 Cloudflare,其他 provider 名稱會被拒絕。 伺服器發布 ACME TXT 摘要,並保留同名的其他 TXT 記錄。

設定需要 provider 區塊:

{
email bonjour@pingclair.com
}
*.example.com {
tls {
auto
dns cloudflare <token>
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 日誌中,這本來就是使用萬用字元的隱私理由。

網站底下的任何名稱都由這一張葉憑證提供。從另一台機器:

終端機視窗
curl -I https://anything.example.com/
HTTP/2 200
content-type: text/html; charset=utf-8
server: Pingclair
終端機視窗
echo | openssl s_client -connect example.com:443 -servername anything.example.com 2>/dev/null \
| openssl x509 -noout -subject -issuer -ext subjectAltName
subject=CN=*.example.com
issuer=C=US, O=Let's Encrypt, CN=YE1
X509v3 Subject Alternative Name:
DNS:*.example.com

🏛️ 來自內部憑證授權單位的憑證

Section titled “🏛️ 來自內部憑證授權單位的憑證”

對於私有的源站——tunnel、內部主機名稱、實驗用的機器——Pingclair 可以自己當憑證授權單位:

https://internal.test {
tls internal
file_server /var/lib/pingclair/html
}

內部憑證授權單位包含根憑證與簽發 90 天葉憑證的中繼憑證。根憑證位於 <store>/pki/authorities/local/root.crt。

用戶端目前還不信任它,所以不加 -k 的請求會失敗。把根憑證安裝到系統的信任儲存區:

終端機視窗
sudo PINGCLAIR_TLS_STORE=/var/lib/pingclair/.local/share/pingclair pingclair trust
✅ 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 也會成功:

終端機視窗
curl -s -o /dev/null -w '%{http_code}\n' https://internal.test/
200

pingclair untrust 可以再把它移除,同樣要加上儲存區前綴。

📌 升級注意。 舊的 internal/ 目錄不會遷移;0.2.0 會建立新的憑證授權單位。每個用戶端都必須重新信任根憑證。

當憑證由其他系統簽發時,把 tls 指向那些檔案:

https://byo.test {
tls {
cert ./certs/byo.crt
key ./certs/byo.key
}
file_server /var/lib/pingclair/html
}

這些檔案必須讓 pingclair 使用者讀得到,因為服務是以該使用者身分執行的。validate 會讀取並解析憑證與金鑰,檢查兩者配對,不開啟監聽器。不存在的路徑會直接被拒絕:

❌ TLS certificate file does not exist: /etc/pingclair/certs/missing.crt
  • 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 會依主機名稱限制驗證失敗的次數。重試前先修好原因,否則重試本身就會變成錯誤。
  • 以服務方式執行:unit、它的重載語意,以及它的日誌。
  • tls:這個指令的每種模式與選項。
  • Pingclairfile:位址、匹配器,以及編譯器接受什麼。