# 🔁 ExĂ©cution comme service L'installateur laisse une unitĂ© `systemd` activĂ©e et dĂ©marrĂ©e. Cette page lit cette unitĂ© ligne par ligne, montre comment la piloter, et dĂ©crit les deux formes d'Ă©chec telles qu'on les voit de l'extĂ©rieur : un serveur qui ne dĂ©marre pas et une configuration que le serveur en cours refuse. ## đŸ§Ÿ Ce que fait l'unitĂ© ```bash systemctl cat pingclair ``` Les clĂ©s qui comptent sont celles-ci : ```text [Service] Type=notify NotifyAccess=main User=pingclair Group=pingclair AmbientCapabilities=CAP_NET_BIND_SERVICE CapabilityBoundingSet=CAP_NET_BIND_SERVICE Environment="RUST_LOG=info" ExecStart=/usr/local/bin/pingclair run /etc/Pingclair/Pingclairfile ExecReload=/bin/kill -USR1 $MAINPID WorkingDirectory=/var/lib/pingclair Restart=on-failure RestartPreventExitStatus=1 RestartSec=5s LimitNOFILE=1048576 LimitNPROC=512 ProtectSystem=full PrivateTmp=true NoNewPrivileges=true ``` Lisez-les dans l'ordre : - `Type=notify` et `NotifyAccess=main` : le serveur prĂ©vient `systemd` quand ses Ă©couteurs sont liĂ©s, donc `systemctl start` bloque jusqu'Ă  ce que le proxy puisse rĂ©pondre, et non jusqu'Ă  ce que le processus existe. - `User=pingclair` avec `AmbientCapabilities=CAP_NET_BIND_SERVICE` : le serveur tourne sans privilĂšges et peut tout de mĂȘme se lier aux ports 80 et 443. - Il n'y a dĂ©libĂ©rĂ©ment aucun `PINGCLAIR_TLS_STORE` ici. Le rĂ©pertoire personnel du compte de service est `/var/lib/pingclair`, donc les certificats vivent dans `/var/lib/pingclair/.local/share/pingclair` : la valeur par dĂ©faut du binaire, le rĂ©pertoire que l'installateur crĂ©e et dans lequel il migre, et le chemin que `pingclair environ` affiche. Nommer un magasin ici serait une seconde rĂ©ponse Ă  une question qui en a dĂ©jĂ  une. l'installateur crĂ©e, que la documentation dĂ©signe et que l'image de conteneur monte. - Il n'y a dĂ©libĂ©rĂ©ment aucun `ExecStartPre` qui lancerait `validate`. Cela ressemble Ă  l'endroit sĂ»r pour ce contrĂŽle, et c'est le piĂšge : `systemd` applique `RestartPreventExitStatus=` au processus principal, pas Ă  une prĂ©-commande qui Ă©choue, donc une configuration que le compilateur refuse Ă©tait retentĂ©e toutes les cinq secondes au lieu de laisser l'unitĂ© en Ă©chec. Le serveur compile le fichier lui-mĂȘme avant de lier quoi que ce soit et sort avec le code 1 quand il le refuse, ce qui est exactement le code pour lequel la politique de redĂ©marrage ci-dessus a Ă©tĂ© Ă©crite — `pingclair run` existe pour ĂȘtre ce processus. - `ExecReload` envoie `SIGUSR1`, le signal que le serveur traite comme « relis le fichier ». `SIGHUP` est ignorĂ© dĂ©libĂ©rĂ©ment, et une unitĂ© qui l'envoyait annonçait un succĂšs pendant que l'ancienne configuration continuait de servir ([issue #66](https://github.com/dorianverlaine/pingclair/issues/66)). Comme `systemd` ne peut observer que la sortie de `kill`, le serveur publie ce qu'il a fait du fichier sur la ligne d'Ă©tat de l'unitĂ© — `Serving (reloaded 1 listener(s) in 323.341”s)`, ou `Reload rejected: 
` — que `systemctl status` affiche. La [section sur le rechargement](#-ce-que-signifie-un-rechargement) plus bas est la version longue. - `Restart=on-failure` avec `RestartPreventExitStatus=1` et `RestartSec=5s` : le code de sortie 1 signifie que la configuration ou le magasin de certificats Ă©tait inutilisable, donc l'unitĂ© reste `failed` pour qu'un opĂ©rateur regarde, au lieu d'ĂȘtre retentĂ©e toutes les cinq secondes. Toute autre dĂ©faillance est redĂ©marrĂ©e. - `ProtectSystem=full`, `PrivateTmp`, `NoNewPrivileges`, `LimitNPROC` et `LimitNOFILE` : le serveur obtient la vue du systĂšme de fichiers et les limites de processus dont il a besoin, et rien de plus. Les deux chemins d'installation Ă©crivent ce mĂȘme fichier. La commande en une ligne embarque une copie octet pour octet de `scripts/pingclair.service` — `just repo-lint` Ă©choue si les deux divergent — donc une installation neuve par `curl | bash` et une installation depuis un dĂ©pĂŽt produisent la mĂȘme unitĂ©, et `systemd-analyze verify /etc/systemd/system/pingclair.service` ne dit rien de cette unitĂ©, sur l'un comme sur l'autre chemin. ## đŸŽ›ïž Piloter le service `pc service` enveloppe `systemctl` pour cette unitĂ© : les deux sont interchangeables. | TĂąche | Avec `pc` | Avec `systemctl` | | --- | --- | --- | | DĂ©marrer | `sudo pc service start` | `sudo systemctl start pingclair` | | ArrĂȘter | `sudo pc service stop` | `sudo systemctl stop pingclair` | | Recharger la configuration | `sudo pc service reload` | `sudo systemctl reload pingclair` | | RedĂ©marrer, aprĂšs un changement d'Ă©couteur ou de politique globale | `sudo pc service restart` | `sudo systemctl restart pingclair` | | État | `pc service status` | `systemctl status pingclair` | | Suivre le journal | — | `journalctl -u pingclair -f` | `pc service status` affiche la vue de l'unitĂ©, y compris la ligne de disponibilitĂ© envoyĂ©e par le serveur : ```text ● 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)" ``` ## 🔁 Ce que signifie un rechargement Une configuration modifiĂ©e dans `/etc/Pingclair/Pingclairfile` atteint le serveur en cours d'exĂ©cution par un signal, et deux commandes l'envoient. `SIGUSR1` est le signal de rechargement, et il n'exige aucune configuration : ```bash sudo kill -USR1 "$(systemctl show -p MainPID --value pingclair)" ``` `pc service reload` — ou `sudo systemctl reload pingclair`, qui est le mĂȘme appel — envoie ce signal Ă  votre place. L'`ExecReload` de l'unitĂ© est `/bin/kill -USR1 $MAINPID` : la commande Ă©vidente est dĂ©sormais celle qui fonctionne. Une unitĂ© qui envoyait `SIGHUP` annonçait un succĂšs et n'appliquait rien, ce que l'[issue #66](https://github.com/dorianverlaine/pingclair/issues/66) a enregistrĂ©. `pingclair reload` atteint le mĂȘme code par l'Admin API et rapporte ce que le serveur a pensĂ© du fichier, ce qui exige l'option `admin` du bloc des options globales : ```text ✅ Configuration reloaded successfully ``` ```text Error: ❌ Reload failed (400): HTTP/1.1 400 Bad Request ``` `systemctl reload` ne peut rapporter qu'une chose : que `kill` a dĂ©livrĂ© le signal. Le serveur lit le fichier ensuite, donc son verdict part sur la ligne d'Ă©tat de l'unitĂ© et dans le journal. `pc service reload` le dit, au lieu d'affirmer que la configuration a Ă©tĂ© appliquĂ©e : ```text $ 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)" ``` Quand le serveur en cours ne peut pas appliquer ce que le fichier demande, l'ancienne configuration continue de servir et la ligne d'Ă©tat dit quel changement a Ă©tĂ© refusĂ©. DĂ©placer le site de `:80` vers `:8080` est le cas courant, parce que la topologie des Ă©couteurs est reconstruite avec les sockets au dĂ©marrage : ```text Status: "Reload rejected: listener topology changed (added: ["[::]:8080"], removed: ["[::]:80"]); restart Pingclair to rebuild H1, H2, H3, and TLS together" ``` Quelle que soit la voie choisie, une configuration qui ne compile pas laisse la prĂ©cĂ©dente en service. Validez d'abord : ```bash sudo pingclair validate /etc/Pingclair/Pingclairfile ``` La politique valable pour tout le processus fait exception. Les options Ă©tablies au dĂ©marrage, comme `trusted_proxies`, ne prennent effet qu'aprĂšs un redĂ©marrage : `sudo pc service restart`. Une configuration qui ajoute ou dĂ©place un Ă©couteur est refusĂ©e de la mĂȘme façon — la ligne d'Ă©tat nomme les adresses ajoutĂ©es et retirĂ©es — parce que le rechargement applique la politique, pas un nouveau socket d'Ă©coute. ## 📜 Journaux L'unitĂ© fixe `RUST_LOG=info` et envoie tout au journal : ```bash sudo journalctl -u pingclair -f sudo journalctl -u pingclair --since '10 min ago' ``` Le dĂ©marrage, les rechargements, le travail sur les certificats et une ligne d'accĂšs par requĂȘte y apparaissent : ```text INFO pingclair::run: 🚀 Starting Pingclair v0.2.0-rc.3 INFO pingclair::run: 📄 Loaded configuration from: /etc/Pingclair/Pingclairfile INFO pingclair::run: 🔔 Received SIGUSR1, reloading configuration from: /etc/Pingclair/Pingclairfile INFO pingclair::run: 📋 Step 1/3: Validating configuration... INFO pingclair::run: ✅ Configuration reload completed successfully in 323.341”s INFO pingclair::run: 📊 1 listener(s) updated INFO 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" ``` Un rechargement que le serveur refuse est journalisĂ© de la mĂȘme façon, avec la raison et la mention que rien n'a changĂ© : ```text 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=RestartRequired ERROR pingclair::run: 💡 Previous configuration remains active, unchanged ``` Pour un journal Ă  part, avec rotation, configurez une destination `log` et Ă©crivez-la sous `/var/log/pingclair`, que l'installateur crĂ©e et attribue Ă  l'utilisateur de service. ## ⚠ Quand le service ne dĂ©marre pas - **`is-active` affiche `activating` et `NRestarts` ne cesse d'augmenter.** C'est le comportement retirĂ© d'une unitĂ© plus ancienne, et il avait deux causes : elle portait `Restart=always` sans `RestartPreventExitStatus`, et elle lançait `validate` comme commande `ExecStartPre`, ce que `RestartPreventExitStatus` ne couvre pas — donc une configuration que le compilateur refuse Ă©tait retentĂ©e toutes les cinq secondes et ressemblait Ă  une unitĂ© qui ne se stabilise jamais plutĂŽt qu'Ă  une unitĂ© en Ă©chec. L'unitĂ© installĂ©e porte `Restart=on-failure` + `RestartPreventExitStatus=1` et aucune prĂ©-commande, et un dĂ©marrage refusĂ© laisse `is-active` Ă  `failed` avec `NRestarts` Ă  zĂ©ro. Sur une installation plus ancienne, arrĂȘtez la boucle avant de dĂ©boguer : `sudo systemctl stop pingclair`, corrigez le fichier, puis `sudo systemctl reset-failed pingclair`. - **`Job for pingclair.service failed because the control process exited with error code`.** Le serveur a refusĂ© la configuration avant de lier quoi que ce soit, et la raison du compilateur est dans le journal, par exemple ``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`.** Le magasin appartient au compte de service. VĂ©rifiez `sudo ls -ld /var/lib/pingclair/.local/share/pingclair` : il doit appartenir Ă  `pingclair`. - **`systemd-analyze verify` signale `Missing '=', ignoring line` pour l'unitĂ© installĂ©e.** Une installation en une ligne plus ancienne Ă©crivait une unitĂ© dont les commentaires avaient Ă©tĂ© dĂ©veloppĂ©s par le shell — 25 lignes de sortie de `--help`, que `systemd` ignore. RĂ©installer avec l'installateur actuel Ă©crit l'unitĂ© telle quelle et le signalement disparaĂźt. - **Rien ne rĂ©pond alors que l'unitĂ© tourne.** Les Ă©couteurs sont liĂ©s et les requĂȘtes n'arrivent pas. VĂ©rifiez le pare-feu du fournisseur puis celui de l'hĂŽte, comme sur la [page d'installation](/fr/start/install/). ## 🧭 Étapes suivantes - [Mise Ă  jour et dĂ©sinstallation](/fr/start/upgrade/) : ce qu'une rĂ©exĂ©cution conserve, et comment tout retirer. - [HTTPS](/fr/start/https/) : les certificats, oĂč vit le magasin, et pourquoi `pingclair trust` a besoin de `PINGCLAIR_TLS_STORE`. - [`log`](/fr/reference/directives/#log) : la destination de journal d'accĂšs que cette page lit depuis le journal systĂšme.