Claude pour sysadmins : 6 tâches serveur courantes
Découvrez 6 tâches que Claude gère bien : lire les logs d’un unit systemd en échec, rédiger des units, relire nginx et Compose, sans exposer vos secrets.
Claude pour les administrateurs système : les conseils d’abord, l’exécution ensuite
Claude est surtout utile aux administrateurs système comme outil de vérification. Vous lui fournissez un extrait de journal, un fichier de configuration, une commande que vous ne reconnaissez pas ou un message d’erreur, puis vous obtenez une explication que vous pouvez vérifier avant de modifier quoi que ce soit sur le serveur. Une mauvaise réponse ne vous coûte rien tant que vous ne l’exécutez pas. La sécurité repose donc entièrement sur le maintien du modèle du côté des conseils.
Six tâches reviennent chaque semaine sur un VPS Linux loué (serveur privé virtuel). Pour chacune, vous trouverez un modèle de prompt efficace, la commande qui permet de vérifier la réponse et le mode d’échec auquel vous devez vous attendre. Aucune ne nécessite que le modèle accède à votre serveur. Vous pouvez copier les éléments depuis un onglet de navigateur ou depuis une fenêtre de votre propre poste de travail, car Claude s’exécute nativement sous Linux comme application de bureau et comme CLI.
L’ordre des opérations est important sur un serveur de production : lisez l’explication, effectuez vous-même le contrôle, puis prenez votre décision. L’autonomie convient à une VM de test. Sur le serveur qui fournit vos services à vos clients, la vérification reste préférable, car le modèle ne peut pas voir l’état réel sur lequel il fonde ses suppositions.
Ce que vous ne devez jamais coller
Tout ce qui figure dans votre invite quitte votre serveur. Quatre catégories doivent rester sur la machine :
- Clés privées :
~/.ssh/id_ed25519,/etc/ssh/ssh_host_*_keyet toute clé TLS (transport layer security) située sous/etc/letsencrypt/live/. - Fichiers d’identifiants :
.env,~/.aws/credentials,/root/.docker/config.jsonet les mots de passe de base de données présents dans un fichier ou une ligne de journal. - Données de compte :
/etc/shadowet/etc/gshadow. Aucune question d’administration système ne nécessite un hash de mot de passe pour obtenir une réponse. - Tout ce qui appartient à vos utilisateurs : adresses e-mail, lignes de commande, journaux de requêtes contenant des cookies de session ou des PII (informations permettant d’identifier une personne).
Les clés publiques peuvent être collées sans risque. Les clés privées ne le peuvent pas. Les deux fichiers se ressemblent à première vue. Lisez donc la première ligne avant de copier : un fichier dont la première ligne contient BEGIN OPENSSH PRIVATE KEY ne doit jamais être placé dans une invite. Bien distinguer vos clés SSH mérite à lui seul dix minutes.
Masquez les données avant de les coller. Ne comptez pas sur votre capacité à repérer un seul token dans 200 lignes :
sudo journalctl -u myapp -n 200 --no-pager | sed -E 's/(token|secret|password|api[_-]?key)[=:][^[:space:]]+/\1=REDACTED/gI'Docker présente un piège particulier. docker compose config insère vos valeurs .env dans la sortie qu’il affiche. Cette sortie est donc un secret, même si le fichier sur disque ne l’était pas. Utilisez docker compose config -q, qui valide la configuration sans rien afficher. Pour connaître la politique générale concernant les éléments qu’un agent est autorisé à voir, consultez la protection des secrets contre les agents d’IA pour l’aspect lié à l’environnement.
Tâche 1 : pourquoi ce service a-t-il échoué ?
Commencez par les deux commandes qui contiennent la réponse :
systemctl status myapp.service --no-pager
sudo journalctl -u myapp.service -b -n 100 --no-pager -o short-isoCollez les deux sorties, avec le contexte que le modèle ne peut pas deviner : la distribution et sa version, votre dernière modification, si le service a déjà fonctionné et depuis combien de temps il est en panne. Demandez d’abord le mécanisme.
Ubuntu 24.04.myapp.servicefonctionnait jusqu’à ce que je modifie l’unité il y a une heure. Voicisystemctl statuset les 100 dernières lignes du journal. Quelle est la première vraie erreur et que signifie-t-elle ? Ne proposez pas encore de correction.
« Ne proposez pas encore de correction » joue un rôle important dans cette invite. Les journaux masquent souvent la première défaillance sous les nouvelles tentatives qu’elle a provoquées. Si vous demandez une correction au modèle, il expliquera la dernière ligne qu’il a vue. La ligne importante se trouve généralement une vingtaine de lignes avant le bruit.
Le résultat attendu ressemble à une ligne telle que Main PID: 1841 (code=exited, status=203/EXEC). Le code de sortie 203/EXEC signifie que le noyau n’a pas pu exécuter le fichier indiqué dans ExecStart : soit le chemin n’existe pas, soit le fichier existe mais n’est pas exécutable. Une ligne #! qui indique un interpréteur non installé produit le même code. Vous pouvez vérifier tous ces éléments avec ls -l et head -1.
Mode d’échec : une cause inventée. Si vous collez trop peu de contenu, le modèle comble les lacunes avec une explication générique, comme « le port est déjà utilisé ». Posez alors cette question : « Quelle ligne du contenu que je vous ai fourni permet de l’affirmer ? » Une cause que personne ne peut relier au texte est une supposition.
Tâche 2 : rédiger une unité systemd ou une entrée cron
Donnez-lui les informations dont un fichier d’unité a besoin : la commande exacte, l’utilisateur sous lequel elle s’exécute, le répertoire de travail, si elle doit attendre le réseau et ce qui doit se produire lorsqu’elle se termine avec un code différent de zéro. Vérifiez ensuite le résultat avant d’activer quoi que ce soit.
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl start myapp.service
systemctl status myapp.service --no-pagersystemd-analyze verify analyse le fichier comme systemd, et détecte ainsi ce qu’une vérification visuelle peut laisser passer. Une directive mal orthographiée affiche /etc/systemd/system/myapp.service:7: Unknown key name 'Enviroment' in section 'Service', ignoring.. Un binaire absent affiche Command /usr/local/bin/myapp is not executable: No such file or directory. Ces deux problèmes restent silencieux pendant daemon-reload. C’est pourquoi une unité peut être chargée correctement, puis échouer au moment de son exécution.
Deux erreurs de rédaction reviennent régulièrement. La première est After=network.target. Cette directive signifie seulement que la pile réseau est configurée, pas qu’une adresse est déjà disponible. Un service qui se lie à une adresse IP précise échoue alors au démarrage avec bind: Cannot assign requested address. La correction consiste à utiliser Wants=network-online.target avec After=network-online.target. La seconde est Type=simple pour un programme qui se détache du terminal : systemd considère le premier processus comme le service, le processus parent se termine immédiatement et l’unité est marquée comme inactive, tandis que le véritable processus continue de s’exécuter sans supervision. C’est l’erreur qu’un modèle risque le plus de vous proposer, car il ne peut pas déterminer à partir de votre commande si le binaire crée un processus fils. Il est donc utile de savoir ce que chaque valeur de Type= garantit à systemd avant d’accepter la proposition.
Pour une planification, vérifiez-la au lieu de la lire :
systemd-analyze calendar 'Mon *-*-* 04:00:00'Cette commande affiche la forme normalisée et la prochaine date d’exécution de l’expression. Elle permet donc de trancher toute discussion sur sa signification. Si vous hésitez entre un timer et une crontab, les services et timers systemd sur un VPS présente les compromis.
Cron comporte un piège dont aucun modèle ne vous avertira si vous ne le demandez pas. Cron exécute les tâches avec un environnement minimal. Ainsi, PATH correspond approximativement à /usr/bin:/bin et votre profil shell n’est jamais lu. Une tâche qui fonctionne lorsque vous la collez dans votre terminal échoue sous cron avec /bin/sh: 1: docker: not found, car ce binaire se trouve dans /usr/local/bin. Utilisez des chemins absolus dans les crontabs. Si l’obligation, dans un fichier d’unité, d’indiquer explicitement l’utilisateur, l’environnement et les dépendances vous semble excessive par rapport à une simple ligne de crontab, les problèmes que systemd a été conçu pour résoudre expliquent l’origine de cette verbosité.
Tâche 3 : vérifier un fichier nginx ou Compose avant sa mise en production
Cette tâche offre le meilleur retour. Collez le fichier, indiquez ce qu’il est censé faire, puis demandez une explication ligne par ligne de ce qu’il fait réellement.
Ce vhost doit servirexample.comen HTTPS et transmettre/apià un service local sur le port 8080. Relisez-le et indiquez tout ce qui ne correspond pas à cette description.
Exécutez ensuite l’outil qui vérifie la syntaxe :
sudo nginx -t
docker compose config -qnginx -t affiche nginx: configuration file /etc/nginx/nginx.conf test is successful, ou indique le fichier et la ligne, comme dans nginx: [emerg] unknown directive "proxy_pas" in /etc/nginx/conf.d/app.conf:12. docker compose config -q n’affiche rien lorsque le fichier est correctement analysé. En revanche, il affiche un message explicite comme yaml: line 7: did not find expected key si votre indentation est incorrecte.
Aucun de ces outils ne vérifie l’intention. Une configuration qui passe nginx -t peut tout de même transmettre les requêtes au mauvais port ou écouter sur 0.0.0.0 alors que vous vouliez 127.0.0.1. C’est là que le modèle est utile, mais aussi là qu’il échoue : si vous lui demandez de corriger une directive, il renvoie souvent tout le fichier réécrit, avec deux de vos directives supprimées discrètement. Demandez les lignes modifiées et la raison de chaque modification, puis effectuez l’édition manuellement.
Vérifiez ce qui est réellement exposé :
sudo ss -tulpnSans sudo, vous voyez les sockets en écoute, mais pas les processus qui les possèdent. Si cette sortie vous surprend, ce que sont les ports et comment Linux les associe est la lecture la plus courte.
Tâche 4 : expliquez une commande inconnue avant de l’exécuter
Collez la commande et posez quatre questions à son sujet : que fait chaque option, qu’écrit-elle, que supprime-t-elle et que se passe-t-il si je l’exécute deux fois ? La dernière question permet de détecter plus de dégâts que les autres.
Prenez find /var/log -name '*.gz' -mtime +7 -delete. Une bonne réponse vous indique que -mtime +7 compte des périodes complètes de 24 heures et ignore la fraction restante. La commande correspond donc aux fichiers vieux d’au moins huit jours, et non de sept jours. Elle vous indique également que find évalue son expression de gauche à droite. Placer -delete avant -name supprime donc tout ce qui se trouve sous le chemin de départ. Le manuel de find contient cette mise en garde, et cette erreur a coûté leur /var/log à certains utilisateurs.
Prenez aussi rsync -a --delete /srv/app/ /backup/app/. Le slash final de la source signifie « le contenu de ce répertoire ». Supprimez-le et vous obtenez /backup/app/app/. Ajoutez --delete et tout ce qui existe dans la destination mais pas dans la source est supprimé. C’est correct pour un miroir, mais désastreux si le chemin source est incorrect.
Vérifiez avec l’outil, pas avec le modèle :
rsync -a --delete --dry-run /srv/app/ /backup/app/ | head -20
find /var/log -name '*.gz' -mtime +7Exécutez le find sans -delete pour obtenir une liste au lieu de provoquer une perte de données.
Mode d’échec : l’hallucination d’options. Le modèle est fiable avec les outils qui disposent de trente ans de documentation, mais beaucoup moins avec les CLI des fournisseurs et les sous-commandes récentes. Il peut alors produire une option parfaitement plausible qui n’existe pas. --help permet de le vérifier en une seconde. Les problèmes de quoting constituent l’autre point faible. Lorsqu’une commande contient une expression $(...), lisez comment la substitution de commande est développée avant l’exécution de la commande au lieu de faire confiance à l’explication.
Tâche 5 : transformer votre historique shell en procédure d’exploitation
Vous venez de passer deux heures à faire fonctionner quelque chose. Ces connaissances sont dans votre historique de terminal et auront disparu le mois prochain.
history 200 > /tmp/session.txtLisez ce fichier et supprimez toute ligne contenant un mot de passe, un token ou un identifiant client avant de l’utiliser ailleurs. L’historique shell est l’un des endroits les plus fiables pour trouver un secret sur une machine Linux, car tout le monde en saisit un directement au moins une fois. Définissez HISTCONTROL=ignorespace dans votre ~/.bashrc : une commande saisie avec un espace au début n’est alors jamais écrite dans l’historique.
Le prompt qui produit une procédure d’exploitation utilisable demande des vérifications, pas seulement des étapes :
Voici une session shell qui a permis d’obtenir une installation Postgres fonctionnelle sur une machine Debian 13 neuve. Rédigez-la sous forme de procédure d’exploitation numérotée. Une commande par étape. Après chaque étape, indiquez la commande qui prouve qu’elle a réussi et décrivez à quoi ressemble une sortie saine. Signalez chaque étape qui dépendait de mon hôte spécifique.
Mode d’échec : une histoire trop propre. Votre session comportait une étape que vous avez corrigée après deux erreurs, et c’est précisément cette étape que le modèle lisse, car le transcript est plus lisible sans elle. Comparez la procédure à votre historique et rétablissez la correction. Le modèle invente également des commandes de vérification plausibles : exécutez donc chaque vérification qu’il propose avant d’enregistrer le fichier. Si la procédure couvre un premier démarrage, comparez-la à ces dix premières minutes sur un nouveau VPS afin de ne pas documenter une version moins fiable d’un problème déjà résolu.
Job 6 : transformer un message d’erreur en correctif
Collez la chaîne exacte, la commande qui l’a produite et la seule chose que vous avez modifiée avant son apparition. Demandez les causes par ordre de probabilité, avec une commande distinctive pour chacune. La réponse devra ainsi être vérifiable.
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use). Classez les causes probables et donnez-moi une commande par cause pour la confirmer ou l’écarter.
Pour cette erreur, le mécanisme ne prête pas à confusion : un autre processus utilise déjà le port 80, et sudo ss -tulpn | grep ':80 ' l’identifie. Il s’agit souvent d’un second master nginx resté actif après un reload qui a échoué, ou d’Apache chargé comme dépendance et démarré par son propre paquet.
Mode d’échec : un correctif qui masque la cause. chmod 777, --privileged, la désactivation de SELinux et l’exécution du service avec root font tous disparaître l’erreur. Refusez tout correctif qui élargit les permissions tant que le modèle n’a pas expliqué pourquoi la permission restrictive a échoué. Cette explication constitue la véritable réponse. Une solution de contournement rend seulement l’erreur silencieuse.
Ce qu’il interprète systématiquement mal
- Il ne peut pas voir votre machine. Chaque réponse dépend de ce que vous avez collé, et il ne vous indiquera pas que l’extrait était trop court.
- Il se trompe selon les versions. Les noms des paquets et les options par défaut varient selon les distributions et les versions, tandis que le modèle fait une moyenne de toutes ces variantes.
- Il reste fluide lorsqu’il se trompe. Un mécanisme inventé ressemble exactement à un mécanisme correct. C’est pourquoi chaque cause ci-dessus est accompagnée d’une commande qui permet de la vérifier.
- Il perd le fil au cours des longues sessions. Les informations fournies au début d’une conversation de deux heures ne contribuent plus aux réponses de la fin.
Ce dernier point relève davantage du fonctionnement pratique que du modèle lui-même. La solution consiste à gérer le contexte dans une longue session Claude Code : des sessions plus courtes, avec une seule tâche par session.
Installer l’agent directement sur le serveur
Tout ce qui précède se limite à des commandes à copier-coller : le modèle ne touche donc jamais à votre machine. Une fois qu’il s’exécute sur le serveur, qu’il lit des fichiers et qu’il exécute des commandes, la nature du risque change : une commande incorrecte peut désormais interrompre un service. Attribuez-lui son propre utilisateur sans privilèges plutôt que root, ne l’exécutez pas sur le serveur de production tant que vous n’avez pas observé son comportement, et créez d’abord un snapshot. Exécuter Claude Code en toute sécurité sur un VPS présente le sandboxing et le modèle de permissions. Exécuter Claude Code dans tmux résout l’autre moitié du problème : une session SSH (secure shell) interrompue arrête un agent au premier plan en plein travail. Créez ce compte comme vous le feriez pour tout compte de service ; utilisateurs avec le principe du moindre privilège sur un VPS décrit cette procédure.
FAQ
Claude peut-il lire directement les journaux de mon serveur ?
Non, pas de lui-même. L’interface de chat ne voit que le texte que vous y collez. Claude Code, exécuté sur le serveur comme outil en ligne de commande, peut lire des fichiers et exécuter des commandes avec les permissions de l’utilisateur qui l’a lancé. Cela implique un niveau de confiance supérieur. Pour une question d’assistance courante, il est plus rapide et plus sûr de coller un extrait de 100 lignes après l’avoir anonymisé que de donner à un agent un accès shell.
Que ne dois-je jamais coller depuis un serveur ?
Les clés privées, les fichiers .env et autres magasins d’identifiants, /etc/shadow, ainsi que toutes les données appartenant à vos utilisateurs. Supprimez les tokens des extraits de journaux avant de les placer dans le prompt. Un cas moins évident : la sortie de docker compose config contient vos valeurs .env interpolées. Utilisez donc docker compose config -q, qui valide le fichier sans rien afficher.
Est-il sûr de laisser Claude exécuter des commandes sur un VPS de production ?
Traitez-le comme un nouvel administrateur sans contexte : la lecture ne pose généralement pas de problème, mais l’écriture doit être vérifiée. En production, demandez une explication, puis exécutez vous-même la commande. Si vous voulez réellement qu’un agent exécute des commandes, donnez-lui un compte dédié sans privilèges, sans accès sudo étendu, et commencez sur un serveur de staging où une erreur vous obligera à reconstruire le système plutôt qu’à gérer une interruption de service.
Pourquoi Claude suggère-t-il une option qui n’existe pas ?
Parce qu’il prédit un texte plausible, et qu’une option plausible ressemble à une vraie option. Cela arrive surtout avec les CLI des éditeurs et les sous-commandes récentes, pour lesquelles la documentation disponible pour le modèle est limitée ou a changé depuis. --help et man font foi. Toute commande qui supprime ou écrase des données doit d’abord être exécutée en mode dry run.
Comment vérifier une unité systemd avant de l’activer ?
Exécutez sudo systemd-analyze verify /etc/systemd/system/myapp.service. Cette commande analyse le fichier avec le parseur de systemd, signale les directives inconnues avec leur numéro de ligne et indique si un binaire ExecStart est absent ou non exécutable. Exécutez ensuite daemon-reload et start, puis lisez systemctl status avant de l’enable, car une unité qui se charge correctement peut tout de même échouer lors de sa première exécution.