以服務方式執行
安裝程式留下一個已啟用、正在執行的 systemd unit。本頁逐條讀這個 unit,示範
如何操作它,並說明兩種故障從外面看是什麼樣子:起不來的服務,以及執行中的伺服器
拒絕新設定。
🧾 這個 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。服務帳號的 home 是/var/lib/pingclair, 所以憑證放在/var/lib/pingclair/.local/share/pingclair:二進位自己的預設值、 安裝程式建立並搬移的目錄,也是pingclair environ印出的路徑。在這裡另寫 一個儲存區,等於給已經有答案的問題再答一次。 - 這裡刻意不寫
ExecStartPre去跑validate。那看起來是放檢查的安全位置,恰恰 也是陷阱:systemd的RestartPreventExitStatus=作用於主行程,不作用於失敗 的前置指令,所以編譯器拒絕的設定會每五秒被重試一次,而不是讓 unit 停在 failed。伺服器自己在綁定任何東西之前編譯檔案,拒絕時以結束碼 1 結束——這正是 上面的重啟策略為之而寫的結束碼,pingclair run的存在就是為了成為那個行程。 ExecReload送出SIGUSR1,也就是伺服器理解為「重新讀檔案」的訊號。SIGHUP被刻意忽略,而過去送出它的 unit 會在舊設定繼續服務的同時回報成功 (issue #66)。systemd只能觀察到kill結束了,所以伺服器把對檔案的判斷發佈到 unit 的 status line 上——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 安裝與從倉庫安裝產出同一個 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) Docs: https://github.com/dorianverlaine/pingclair Main PID: 1808 (pingclair) Status: "Serving (reloaded 1 listener(s) in 323.341µs)"🔁 重載意味著什麼
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 的 status line 與日誌裡。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)"執行中的伺服器無法套用檔案所要求的內容時,舊設定會繼續服務,status line 會指出
被拒絕的是哪一處改動。把站台從 :80 搬到 :8080 是最常見的情形,因為監聽器
拓撲是啟動時連通訊端一起建立的:
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。改動監聽器的設定也會被同樣地拒絕——
status line 會列出新增與移除的位址——因為重載套用的是策略,不是新的監聽
通訊端。
unit 設定 RUST_LOG=info,把所有內容送進 journal:
sudo journalctl -u pingclair -fsudo journalctl -u pingclair --since '10 min ago'啟動、重載、憑證工作,以及每個請求一行存取日誌都會出現在那裡:
INFO pingclair::run: 🚀 Starting Pingclair v0.2.0-rc.3INFO pingclair::run: 📄 Loaded configuration from: /etc/Pingclair/PingclairfileINFO pingclair::run: 🔔 Received SIGUSR1, reloading configuration from: /etc/Pingclair/PingclairfileINFO pingclair::run: 📋 Step 1/3: Validating configuration...INFO 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 sink,寫到安裝程式建立並交給服務使用者的
/var/log/pingclair 底下。
⚠️ 服務起不來時
Section titled “⚠️ 服務起不來時”is-active一直顯示activating,NRestarts不斷上升。 這是安裝出來的 舊 unit 已經退役的行為:它帶著Restart=always卻沒有RestartPreventExitStatus,所以伺服器拒絕的設定每五秒被重試一次,看起來不是 一個「失敗一次」的 unit,而是「永遠不收斂」的 unit。還有第二個原因:它把validate當作ExecStartPre跑,而RestartPreventExitStatus不覆蓋它。 現在安裝出來的 unit 帶Restart=on-failure+RestartPreventExitStatus=1, 沒有前置指令,被拒絕的啟動會讓is-active停在failed、NRestarts停在 0。在舊安裝上,除錯前先停掉迴圈:sudo systemctl stop pingclair,改好檔案, 然後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 在跑但外面沒有任何應答。 監聽器已綁定,請求沒到達。和 安裝 一節一樣,先查服務商防火牆,再查主機自身規則。
