Claude pour sysadmins : conseils Linux sans exécution
Découvrez 6 tâches serveur utiles avec Claude : logs systemd, unités, fichiers nginx et Compose. Vérifiez chaque réponse et ne collez jamais vos secrets.
Claude pour les sysadmins : les conseils d’abord, l’exécution ensuite
Claude est particulièrement utile aux sysadmins comme outil de relecture. Vous lui fournissez un extrait de log, un fichier de configuration, une commande que vous ne reconnaissez pas ou un message d’erreur. Il vous renvoie une explication que vous pouvez vérifier avant de modifier quoi que ce soit sur le serveur. Une réponse incorrecte ne vous coûte rien tant que vous ne l’exécutez pas. La sécurité repose donc sur le maintien du modèle du côté des conseils.
Sur un Linux VPS (virtual private server) loué, six tâches reviennent chaque semaine. 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 à prévoir. Aucune ne nécessite que le modèle accède à votre serveur.
L’ordre des opérations est important sur un serveur de production : lisez l’explication, exécutez vous-même la vérification, puis prenez votre décision. L’autonomie convient à une VM de test. Sur le serveur qui fournit vos services à vos clients, la relecture est préférable, car le modèle ne peut pas voir l’état réel du système sur lequel il formule ses hypothèses.
Ce que vous ne devez jamais coller
Tout le contenu de votre prompt 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 comptes :
/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 données personnelles (PII, personally identifiable information).
Les clés publiques peuvent être collées sans risque. Les clés privées, non. Les deux fichiers se ressemblent au premier coup d’œil. 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 inclus dans un prompt. Bien distinguer vos clés SSH mérite à lui seul dix minutes.
Masquez les données avant de coller le contenu. 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 contient donc un secret, même si le fichier sur le disque n’en contenait pas. Utilisez docker compose config -q, qui valide la configuration sans rien afficher. Pour connaître la politique générale sur les éléments qu’un agent est autorisé à consulter, consultez la protection des secrets contre les agents IA concernant l’environnement d’exécution.
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 résultats 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 ligne correspond à la première véritable erreur et que signifie-t-elle ? Pas de correction pour l’instant.
« Pas de correction pour l’instant » est important dans cette demande. Les journaux masquent souvent la première erreur sous les tentatives répétées 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.
Vous obtiendrez une ligne comme 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 points avec ls -l et head -1.
Mode d’échec : une cause inventée. Si vous collez trop peu de contenu, le modèle comble le manque avec une explication générique, par exemple « le port est déjà utilisé ». Posez alors une question de contrôle : « quelle ligne de ce 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
Indiquez les informations dont le fichier d’unité a besoin : la commande exacte, l’utilisateur qui l’exécute, le répertoire de travail, s’il doit attendre que le réseau soit disponible et ce qui doit se passer en cas de sortie 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 les erreurs qu’un contrôle visuel 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 manquant affiche Command /usr/local/bin/myapp is not executable: No such file or directory. Ces deux erreurs restent silencieuses pendant daemon-reload, ce qui explique qu’une unité puisse se charger correctement tout en échouant au moment de son exécution.
Deux erreurs de rédaction reviennent souvent. La première concerne After=network.target, qui signifie seulement que la pile réseau est configurée, et non 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 concerne Type=simple pour un programme qui se met en daemon : systemd considère le premier processus comme le service, le processus parent se termine immédiatement et l’unité est marquée comme arrêtée, tandis que le véritable processus continue de s’exécuter sans supervision.
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, l’article Services et timers systemd sur un VPS présente les compromis.
Cron comporte un piège qu’aucun modèle ne signalera si vous ne le demandez pas. Cron exécute les tâches avec un environnement minimal. Ainsi, PATH vaut à peu près /usr/bin:/bin et votre profil shell n’est jamais lu. Une tâche qui fonctionne lorsque vous la collez dans votre terminal échoue avec cron et affiche /bin/sh: 1: docker: not found, car ce binaire se trouve dans /usr/local/bin. Utilisez des chemins absolus dans les crontabs.
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 nom du fichier et la ligne concernée, 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é, et affiche un message explicite comme yaml: line 7: did not find expected key si l’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 vers le 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 faites la modification manuellement.
Vérifiez ce que vous avez 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, lisez ce guide plus court sur les ports et la manière dont Linux les associe.
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 d’éviter davantage 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 âgés 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. Ce second point apparaît comme un avertissement dans la page de manuel de find. Il a déjà coûté leur /var/log à certaines personnes.
Prenez aussi rsync -a --delete /srv/app/ /backup/app/. Le slash final dans la source signifie « le contenu de ce répertoire ». Supprimez-le et vous obtenez /backup/app/app/. Ajoutez --delete et tout ce qui manque dans la source est supprimé de la destination. 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 d’une suppression.
Mode d’échec : hallucination d’option. Le modèle est fiable avec les outils qui disposent de trente ans de documentation, mais beaucoup moins avec les CLI des fournisseurs (interfaces de ligne de commande) et les sous-commandes récentes. Il peut produire une option parfaitement plausible qui n’existe pas. --help permet de le vérifier en une seconde. Les guillemets constituent l’autre point faible. Lorsqu’une commande contient une expression $(...), lisez comment la substitution de commande se développe avant l’exécution de la commande au lieu de faire confiance à l’explication.
Tâche 5 : transformer votre historique shell en runbook
Vous venez de passer deux heures à faire fonctionner quelque chose. Ces connaissances restent dans votre scrollback et auront disparu le mois prochain.
history 200 > /tmp/session.txtLisez ce fichier et supprimez chaque ligne contenant un mot de passe, un token ou un identifiant client avant de le transmettre. 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 dans la commande au moins une fois. Définissez HISTCONTROL=ignorespace dans votre ~/.bashrc : une commande saisie avec un espace initial n’est alors jamais écrite dans l’historique.
Le prompt qui produit un runbook exploitable demande des vérifications, pas seulement des étapes :
Ceci est une session shell qui a transformé une machine Debian 13 fraîchement installée en installation PostgreSQL fonctionnelle. Rédigez-la sous forme de runbook numéroté. 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 toute é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 exécutée incorrectement deux fois avant de la corriger. C’est précisément cette étape que le modèle lisse, car le transcript paraît plus clair sans elle. Comparez le runbook avec votre historique et réintégrez la correction. Le modèle invente également des commandes de vérification plausibles. Exécutez donc chaque vérification qu’il écrit avant d’enregistrer le fichier. Si le runbook couvre un premier démarrage, comparez-le à ces dix premières minutes sur un nouveau VPS afin de ne pas documenter une version moins efficace d’un problème déjà résolu.
Tâche 6 : transformer un message d’erreur en solution
Collez la chaîne exacte, la commande qui l’a produite et la seule modification effectuée juste avant son apparition. Demandez les causes par ordre de probabilité, avec une commande permettant de distinguer chaque cause. La réponse doit ainsi pouvoir être vérifiée.
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 est sans ambiguïté : un autre processus utilise déjà le port 80, et sudo ss -tulpn | grep ':80 ' indique lequel. Il s’agit souvent d’un second processus master nginx laissé après un reload échoué, ou d’Apache, installé comme dépendance et démarré par son propre paquet.
Mode d’échec : une solution qui masque la cause. chmod 777, --privileged, la désactivation de SELinux et l’exécution du service avec le compte root font tous disparaître l’erreur. Refusez toute solution 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 ne fait que rendre l’erreur silencieuse.
Ce qu’il fait systématiquement mal
- Il ne voit pas votre serveur. Chaque réponse dépend de ce que vous avez collé, et il ne vous indiquera pas que l’extrait était trop court.
- Il perd le fil entre les versions. Les noms de paquets et les options par défaut changent selon les distributions et les versions, tandis que le modèle fait une moyenne de toutes ces variantes.
- Il est fluide même 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 cessent d’influencer les réponses vers la fin.
Ce dernier point relève davantage du fonctionnement pratique que du modèle lui-même. Gérer le contexte dans une longue session Claude Code constitue la solution concrète : des sessions plus courtes, une seule tâche par session.
Installer l’agent directement sur le serveur
Tout ce qui précède consiste à copier-coller des commandes : le modèle n’interagit donc jamais avec votre machine. Une fois qu’il s’exécute sur le serveur, lit des fichiers et exécute des commandes, le risque change de nature : une commande incorrecte peut maintenant interrompre un service. Créez un utilisateur non privilégié dédié plutôt que d’utiliser 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 couvre le sandboxing et le modèle de permissions. Piloter Claude Code dans tmux résout l’autre problème : la fermeture d’une session SSH (secure shell) interrompt un agent au premier plan au milieu de son travail. Créez ce compte comme vous le feriez pour n’importe quel compte de service ; utilisateurs avec le principe du moindre privilège sur un VPS détaille cette méthode.
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 plus élevé. Pour une question de support courante, il est plus rapide et plus sûr de coller un extrait de 100 lignes après anonymisation que d’accorder un accès shell à un agent.
Que ne dois-je jamais coller depuis un serveur ?
Les clés privées, les fichiers .env et autres stockages d’identifiants, /etc/shadow, ainsi que toutes les données appartenant à vos utilisateurs. Supprimez les tokens des extraits de journaux avant de les transmettre 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 qui ne connaît pas votre environnement : la lecture ne pose généralement pas de problème, mais l’écriture doit être contrôlée. En production, demandez l’explication, puis exécutez vous-même la commande. Si vous voulez vraiment qu’un agent exécute des commandes, donnez-lui un compte dédié sans privilèges, sans accès sudo global, et commencez sur une machine de staging où une erreur vous impose une reconstruction plutôt qu’une interruption de service.
Pourquoi Claude propose-t-il un flag qui n’existe pas ?
Parce qu’il prédit un texte plausible, et qu’un flag plausible ressemble à un flag réel. 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 autorité. Toute commande qui supprime ou écrase des données doit d’abord être exécutée en 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 parser utilisé par systemd, signale les directives inconnues avec leur numéro de ligne et indique lorsqu’un binaire ExecStart est absent ou non exécutable. Exécutez ensuite daemon-reload, start et consultez 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.