以服務方式執行
安裝程式會建立並啟用 systemd 服務。本頁說明服務設定、操作命令,以及啟動失敗或重載遭拒時的檢查方式。
🧾 unit 做了什麼
Section titled “🧾 unit 做了什麼”systemctl cat pingclair重要的設定鍵如下:
[Service]Type=notifyNotifyAccess=mainUser=pingclairGroup=pingclairAmbientCapabilities=CAP_NET_BIND_SERVICECapabilityBoundingSet=CAP_NET_BIND_SERVICEEnvironment="RUST_LOG=info"ExecStart=/usr/local/bin/pingclair run /etc/Pingclair/PingclairfileExecReload=/bin/kill -USR1 $MAINPIDWorkingDirectory=/var/lib/pingclairRestart=on-failureRestartPreventExitStatus=1RestartSec=5sLimitNOFILE=1048576LimitNPROC=512ProtectSystem=fullPrivateTmp=trueNoNewPrivileges=true依序來看:
Type=notify與NotifyAccess=main:伺服器在監聽器綁定完成時主動通知systemd,因此systemctl start會等待監聽器就緒後才返回。User=pingclair搭配AmbientCapabilities=CAP_NET_BIND_SERVICE:伺服器以非特權身分執行,仍然可以綁定 80 與 443 連接埠。- 這裡刻意沒有
PINGCLAIR_TLS_STORE。服務帳號的家目錄是/var/lib/pingclair,憑證自然落在/var/lib/pingclair/.local/share/pingclair:這是二進位檔的預設值、安裝程式建立並遷移進去的目錄,也是pingclair environ印出的路徑。再多指定一個儲存區,等於替一個已有答案的問題硬塞第二個答案。 - unit 不使用
ExecStartPre執行validate,因為RestartPreventExitStatus=只適用於主行程,無法阻止失敗的前置命令被持續重試。伺服器會在綁定監聽器前編譯設定;無效設定以結束碼 1 終止,讓 unit 保持失敗狀態。 ExecReload送出SIGUSR1,伺服器把這個訊號視為「重新讀取檔案」。SIGHUP會被刻意忽略;曾有 unit 送出它,回報成功,舊設定卻繼續在提供服務(issue #66)。由於systemd只能看到kill結束了,伺服器會把它對檔案的處理結果發布在這個 unit 的狀態列上——Serving (reloaded 1 listener(s) in 323.341µs)或Reload rejected: …——systemctl status會顯示出來。完整說明見下方的重載一節。Restart=on-failure搭配RestartPreventExitStatus=1與RestartSec=5s:結束碼 1 代表設定或憑證儲存區完全無法使用,所以 unit 會停在failed,等維運人員查看,而不是每五秒重試一次。其他任何失敗都會重啟。ProtectSystem=full、PrivateTmp、NoNewPrivileges、LimitNPROC與LimitNOFILE:伺服器只拿到它需要的檔案系統視野與行程限制,僅此而已。
兩種安裝路徑寫出的都是同一個檔案。一行式安裝內嵌了 scripts/pingclair.service 逐位元組相同的副本——兩者一旦不同,just repo-lint 就會失敗——所以全新的 curl | bash 安裝與從原始碼 checkout 安裝會產生相同的 unit,而且在兩種路徑上,systemd-analyze verify /etc/systemd/system/pingclair.service 都不會對這個 unit 提出任何問題。
🎛️ 操作服務
Section titled “🎛️ 操作服務”pc service 包裝了針對這個 unit 的 systemctl,兩者可以互換:
| 工作 | 使用 pc |
使用 systemctl |
|---|---|---|
| 啟動 | sudo pc service start |
sudo systemctl start pingclair |
| 停止 | sudo pc service stop |
sudo systemctl stop pingclair |
| 重載設定 | sudo pc service reload |
sudo systemctl reload pingclair |
| 監聽器或全行程層級的變更後重啟 | sudo pc service restart |
sudo systemctl restart pingclair |
| 狀態 | pc service status |
systemctl status pingclair |
| 追蹤日誌 | — | journalctl -u pingclair -f |
pc service status 會印出 unit 自己的視角,包括伺服器送出的就緒狀態:
● pingclair.service - Pingclair High-Performance Web Server Loaded: loaded (/etc/systemd/system/pingclair.service; enabled; preset: enabled) Active: active (running) since Tue 2026-09-22 05:57:21 UTC; 18s ago Docs: https://pingclair.com/start/service/ Main PID: 27630 (pingclair) Status: "Serving"🔁 重載意味著什麼
Section titled “🔁 重載意味著什麼”修改過的 /etc/Pingclair/Pingclairfile 透過一個訊號送達執行中的伺服器,有兩個命令會送出它。
SIGUSR1 就是重載訊號,它本身不需要任何設定:
sudo kill -USR1 "$(systemctl show -p MainPID --value pingclair)"pc service reload——或是完全相同的 sudo systemctl reload pingclair——會替你送出這個訊號。unit 的 ExecReload 是 /bin/kill -USR1 $MAINPID,所以最直覺的那個命令現在就是能用的那個;過去送出 SIGHUP 的 unit 會回報成功卻什麼都沒套用,這正是 issue #66 記錄的問題。
pingclair reload 透過 Admin API 走到同一段程式碼,並回報伺服器對檔案的判定,因此需要全域選項區塊裡的 admin 選項:
✅ Configuration reloaded successfullyError: ❌ Reload failed (400): HTTP/1.1 400 Bad Requestsystemctl reload 只能回報一件事:kill 送達了訊號。伺服器是在那之後才讀取檔案,所以判定結果會改送到 unit 的狀態列與 journal。pc service reload 會照實這樣說,而不是宣稱設定已經套用:
$ sudo pc service reload✅ Reload signal delivered to pingclair.serviceℹ️ The result lands a moment later: `systemctl status pingclair` or `journalctl -u pingclair -n 20`$ systemctl status pingclair --no-pager | grep Status Status: "Serving (reloaded 1 listener(s) in 323.341µs)"執行中的伺服器無法套用新檔案的要求時,舊設定會繼續提供服務,狀態列會指出哪一項變更被拒絕。最常見的情況是把網站從 :80 搬到 :8080,因為監聽器拓撲在啟動時就連同 socket 一起定型了:
Status: "Reload rejected: listener topology changed (added: ["[::]:8080"], removed: ["[::]:80"]); restart Pingclair to rebuild H1, H2, H3, and TLS together"不論走哪條路,無法編譯的設定都只會讓舊設定繼續跑,網站照常回應。請先驗證:
sudo pingclair validate /etc/Pingclair/Pingclairfile執行中的行程無法吸收的變更屬於例外。啟動時固定的全域政策(例如 trusted_proxies)變更會被重載拒絕,必須重啟;行程日誌設定可重載。請使用sudo pc service restart。新增或搬移監聽器的設定也一樣——狀態列會列出新增與移除的位址——因為重載只更新政策,不換監聽 socket。
🛑 停止意味著什麼
Section titled “🛑 停止意味著什麼”systemctl stop 送出 SIGTERM。伺服器先讓 /ready 回應 503,停止接受新請求,再等待執行中的請求完成,最長為 grace_period(預設 30 秒)。期限到達時關閉仍存活的 QUIC 連線。重啟在兩個行程之間會有連線空窗;只改網站政策時優先重載。
unit 設定了 RUST_LOG=info,並把所有輸出送到 journal:
sudo journalctl -u pingclair -fsudo journalctl -u pingclair --since '10 min ago'啟動、重載、憑證作業,以及每個請求一行的存取紀錄都會出現在那裡:
INFO pingclair::run: 📄 Loaded configuration from: /etc/Pingclair/PingclairfileINFO pingclair::run: 🔔 Received SIGUSR1, reloading configuration from: /etc/Pingclair/PingclairfileINFO pingclair::run: ✅ Configuration reload completed successfully in 323.341µsINFO pingclair::run: 📊 1 listener(s) updatedINFO pingclair_proxy::server: 📝 Access request_id="65c09fa25d457-6" method="GET" host="localhost" path="/" status=200 bytes=18747 duration_ms=0 remote_ip=::1 user_agent="curl/8.18.0"伺服器拒絕的重載也會以同樣方式記錄,附上原因,並註明沒有任何變更:
ERROR pingclair::run: ❌ Configuration reload rejected after 414.491µs: listener topology changed (added: ["[::]:8080"], removed: ["[::]:80"]); restart Pingclair to rebuild H1, H2, H3, and TLS together kind=RestartRequiredERROR pingclair::run: 💡 Previous configuration remains active, unchanged若要一份獨立、可輪替的日誌,請設定 log 輸出,寫到 /var/log/pingclair 底下;這個目錄由安裝程式建立,並交給服務使用者擁有。
⚠️ 服務啟動失敗時
Section titled “⚠️ 服務啟動失敗時”is-active顯示activating,NRestarts不斷增加。 舊版 unit 的Restart=always或ExecStartPre驗證命令可能造成持續重試。目前的 unit 使用Restart=on-failure、RestartPreventExitStatus=1,且不執行前置驗證。請先執行sudo systemctl stop pingclair,更新 unit 並修正設定,再執行sudo systemctl reset-failed pingclair。Job for pingclair.service failed because the control process exited with error code。 伺服器在綁定任何東西之前就拒絕了設定,編譯器給的理由在 journal 裡,例如Error: ❌ Configuration Error: Compile error: Unsupported feature: `encode br`: Brotli is not implemented for proxied responses; use `encode zstd gzip`。TLS store /var/lib/pingclair/.local/share/pingclair is not writable: Permission denied。 儲存區屬於服務帳號。請檢查sudo ls -ld /var/lib/pingclair/.local/share/pingclair;擁有者應該是pingclair。systemd-analyze verify對已安裝的 unit 回報Missing '=', ignoring line。 舊版的一行式安裝寫出的 unit,其註解被 shell 展開了——變成 25 行--help輸出,systemd會忽略它們。用目前的安裝程式重新安裝,就會原封不動地寫出 unit,這則回報也會消失。- unit 在執行,卻沒有任何回應。 監聽器已綁定,請求卻沒有抵達。請依安裝頁面的說明,先檢查供應商的防火牆,再檢查主機本身的。
