Exploiter Claude Code en toute sécurité sur son propre VPS
Un VPS Debian renforcé permet de garder les sessions Claude Code accessibles en permanence. Ce guide couvre le compte utilisateur, les clés SSH, le pare-feu, l’hygiène des données, tmux et l’accès sécurisé depuis un iPhone.
Sur son propre ordinateur, une session Claude Code s’interrompt inévitablement lorsque l’ordinateur portable se met en veille ou que la connexion réseau est coupée. Un VPS continue de fonctionner et reste accessible depuis plusieurs appareils. En même temps, il est connecté en permanence à l’Internet public et fait l’objet de scans automatisés peu après son démarrage.
Ce guide réunit ces deux exigences : Claude Code reste disponible dans une session tmux, tandis que le serveur Debian n’offre vers l’extérieur qu’une connexion SSH protégée par clé. Le renforcement n’est pas spécifique à Claude et convient également à d’autres serveurs Linux accessibles publiquement.
Pourquoi un VPS peut être pertinent
Par rapport à une installation purement locale, le serveur offre trois avantages pratiques :
- Persistance. Dans une session
tmux, Claude continue de fonctionner même si la connexion SSH est interrompue. Une tâche qui prend dix minutes ou une heure s’achève sans que l’ordinateur portable doive rester ouvert. - Accessibilité. La même session est accessible depuis le poste de travail, l’ordinateur portable et l’iPhone. On lance une tâche depuis son bureau et on consulte le résultat en déplacement.
- Contrôle des données. On décide soi-même de ce qui se trouve sur le serveur. Aucun service de synchronisation, aucune donnée d’accès sauvegardée accidentellement, à condition de procéder soigneusement lors de la migration (voir plus bas).
tmux est donc une fonction de disponibilité et de confort, et non une mesure de sécurité. Le vrai travail réside dans la sécurisation.
Situation de départ
La base est Debian 13 (Trixie), installée en version minimale, sans bureau ni services réseau supplémentaires. Le fournisseur met à disposition un pare-feu en amont qui s’applique indépendamment du système d’exploitation. L’objectif est un serveur sur lequel seul SSH est accessible depuis l’extérieur, et uniquement avec des clés protégées par phrase secrète.
1. Mettre le système à jour
Immédiatement après l’installation, mettre à jour l’ensemble des paquets :
sudo apt update
sudo apt full-upgrade
Contrairement à upgrade, full-upgrade résout aussi les dépendances qui nécessitent de nouveaux paquets ou la suppression de paquets. Sur un système fraîchement installé, c’est la bonne approche pour appliquer réellement toutes les mises à jour de sécurité disponibles. Redémarrer une fois après les mises à jour du noyau.
2. Un utilisateur dédié plutôt que root
Travailler en tant que root est inutilement risqué : chaque faute de frappe s’applique à l’ensemble du système, et la connexion root directe est la première chose que tentent les attaques automatisées. Il faut donc créer un utilisateur dédié (ici claude) disposant de droits sudo pour les cas où ils sont nécessaires :
sudo adduser claude
sudo usermod -aG sudo claude
Désormais, toute l’administration passe par claude et sudo, et non plus par l’accès root direct.
3. Clés Ed25519 avec phrase secrète, une par appareil
L’authentification doit s’effectuer exclusivement avec des clés SSH, et non avec des mots de passe. Ed25519 est le standard actuel : court, rapide et cryptographiquement solide. L’essentiel est que la clé soit générée sur le client, donc sur le PC et non sur le serveur, puis protégée par une phrase secrète. La phrase secrète constitue la deuxième ligne de défense si la clé privée tombe un jour entre de mauvaises mains.
Sur le PC :
ssh-keygen -t ed25519 -C "pc-thinkpad"
Le commentaire (-C) désigne l’appareil. Cela s’avère utile par la suite : une clé distincte est générée pour chaque appareil, une pour le PC et une autre pour l’iPhone. Si un appareil est perdu, il suffit de supprimer précisément sa clé publique de ~/.ssh/authorized_keys, sans devoir redéployer tous les autres accès.
Seule la clé publique doit être placée sur le serveur. La clé privée ne quitte jamais l’appareil. À la fin, authorized_keys ne contient que des clés publiques, chacune accompagnée du commentaire de son appareil :
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...pc pc-thinkpad
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...ios iphone-15
Transférer initialement la clé publique du PC. Tant que l’authentification par mot de passe est encore active, le plus simple est d’utiliser :
ssh-copy-id claude@SERVER
Tester ensuite que la connexion avec la clé fonctionne avant de désactiver l’authentification par mot de passe à l’étape suivante. Les permissions de fichiers doivent être correctes, sinon sshd ignore le fichier : ~/.ssh à 700, authorized_keys à 600.
4. Renforcer SSH : ni root ni mot de passe
La configuration du serveur se trouve dans /etc/ssh/sshd_config et (sur Debian 13) dans les fichiers Drop-in sous /etc/ssh/sshd_config.d/. Les modifications doivent être placées dans un fichier Drop-in dédié ; le fichier principal reste ainsi intact et les mises à jour de paquets n’écrasent rien. Créer le fichier /etc/ssh/sshd_config.d/99-haertung.conf :
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
Cela désactive la connexion root directe et l’authentification par mot de passe. Désormais, seules les personnes possédant une clé privée correspondante peuvent se connecter. Avant de recharger, vérifier la syntaxe de la configuration :
sudo sshd -t
Si sshd -t ne retourne rien, le fichier est valide. Ne recharger qu’ensuite :
sudo systemctl reload ssh
Important : laisser la session SSH existante ouverte et tester le nouvel accès dans un second terminal. L’ancienne session ne doit être fermée qu’une fois la connexion par clé vérifiée. Cette précaution réduit pratiquement à zéro le risque de se verrouiller l’accès. Une erreur de configuration peut autrement entraîner la perte de tout accès.
5. Déplacer SSH vers un port inhabituel
Le port standard 22 est testé en permanence par des bots. Le remplacer par un port élevé librement choisi (dans l’exemple 61417) laisse dans le vide la majeure partie de ce bruit automatisé. Ce n’est explicitement pas un gain de sécurité à proprement parler : changer de port ne remplace pas une authentification forte, cela réduit seulement le volume de journaux et la charge des scans. L’obligation d’utiliser des clés de l’étape 4 reste la véritable protection.
Le choix du port n’est pas arbitraire. L’IANA distingue trois zones : les ports 0–1023 (well-known ports) sont réservés aux services standards (SSH lui-même sur 22, HTTP sur 80, HTTPS sur 443), nécessitent root pour s’y lier et n’ont rien à faire pour un port SSH choisi librement ; ce sont précisément les ports attendus par les scanners comme par les services standards qui pourraient être installés ultérieurement. Les ports 1024–49151 (ports enregistrés) sont attribués sur demande à des applications individuelles, par exemple 3306 (MySQL), 5432 (PostgreSQL), 6379 (Redis) ou 8080/8443 comme alternatives HTTP répandues ; un port choisi au hasard dans cette plage entre facilement en conflit ultérieurement avec un logiciel qui attend précisément son port enregistré. Les ports 49152–65535 (ports dynamiques/privés) ne sont attribués à aucun service selon l’IANA et sont prévus pour des usages temporaires et privés : c’est la plage appropriée pour un port permanent choisi par soi-même.
Une réserve subsiste : de nombreux systèmes Linux, dont Debian, utilisent une partie de cette même plage comme port source pour leurs propres connexions sortantes (net.ipv4.ip_local_port_range, par défaut autour de 32768–60999). Un service qui écoute durablement n’entre pas réellement en conflit avec cela, car le noyau n’attribue pas un port déjà lié, mais un port supérieur à 60999 évite également cette ambiguïté théorique. L’exemple de cet article (61417) se situe donc délibérément dans cette plage. Avant le changement, vérifier également avec ss -lntup (voir étape 7) que le port choisi n’est pas déjà occupé sur son propre serveur.
Avec Debian 13, il y a une particularité : SSH peut être démarré via l’activation par socket systemd. Si c’est le cas, l’indication Port dans sshd_config est tout simplement ignorée ; le port doit alors être défini au niveau du socket. Vérifier d’abord quelle situation s’applique :
systemctl is-enabled ssh.socket
Si la commande répond enabled, SSH fonctionne via le socket. Modifier alors le port à cet endroit :
sudo systemctl edit ssh.socket
Dans l’éditeur, saisir les lignes suivantes. La première ligne ListenStream=, vide, supprime le port 22 prédéfini ; la seconde définit le nouveau :
[Socket]
ListenStream=
ListenStream=61417
Appliquer ensuite les changements :
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
Si l’activation par socket n’est pas active (disabled), il faut à la place ajouter Port 61417 au fichier Drop-in de l’étape 4, puis exécuter sudo sshd -t et sudo systemctl restart ssh.
Ici aussi, il faut d’abord ouvrir le nouveau port dans le pare-feu (étape suivante), puis se connecter et tester, en laissant l’ancienne session ouverte jusqu’à ce que l’accès par le nouveau port soit confirmé.
6. Pare-feu : fermé par défaut
Le pare-feu du fournisseur situé en amont constitue la limite la plus efficace, car il intercepte les paquets avant même qu’ils n’atteignent le système d’exploitation. Deux règles de base :
- Action par défaut pour les connexions entrantes : DROP. Tout ce qui n’est pas explicitement autorisé est rejeté, sans commentaire ni retour à l’expéditeur.
- Une seule exception : TCP entrant sur le port cible
61417. Rien d’autre ne doit être accessible depuis l’extérieur.
Le trafic sortant reste autorisé. C’est intentionnel : le serveur doit pouvoir télécharger des paquets, synchroniser l’heure et atteindre l’API pour Claude Code. Un filtrage sortant restrictif apporte peu de protection supplémentaire pour un serveur individuel, mais rend l’exploitation sensiblement plus contraignante.
Pour une défense en profondeur supplémentaire, les mêmes règles peuvent être dupliquées côté hôte avec nftables ou ufw. Pour la configuration décrite, le pare-feu du fournisseur suffit.
7. Vérifier la surface d’attaque
Après le renforcement, contrôler ce que le serveur propose réellement vers l’extérieur. Deux commandes suffisent. Premièrement : quels services écoutent sur quelles adresses ?
sudo ss -lntup
La colonne d’adresse est déterminante : un service sur 0.0.0.0 ou [::] est accessible depuis l’extérieur, un service sur 127.0.0.1 ou [::1] ne l’est que localement. Dans l’état sécurisé, seul SSH devrait apparaître publiquement. Des services tels que chronyd (synchronisation de l’heure) peuvent apparaître, mais uniquement liés à des adresses locales. Si chronyd écoute exclusivement sur 127.0.0.1 et ::1, il n’est pas joignable depuis l’extérieur et est donc sans risque.
Deuxièmement : existe-t-il des services système défaillants indiquant un problème de configuration ?
systemctl --failed
La réponse devrait être 0 loaded units listed, sans le moindre service défaillant. Les unités défaillantes ne sont pas seulement un problème d’exploitation, mais aussi potentiellement un problème de sécurité si elles cachent un service réseau partiellement démarré ou mal configuré.
8. Installer et exploiter Claude Code
Claude Code nécessite un environnement d’exécution Node.js récent. Après l’avoir installé, configurer la CLI selon les instructions officielles et s’authentifier à nouveau sur le serveur, sans téléverser les données d’accès locales (nous y revenons juste après).
Pour une exploitation durable avec tmux :
tmux new -s claude
Démarrer Claude dans la session. Avec Ctrl-b, puis d, on se détache de la session sans y mettre fin ; Claude continue de fonctionner. Pour y revenir :
tmux attach -t claude
Ainsi, une tâche en cours survit aux connexions interrompues, aux changements d’appareil et à la mise en veille nocturne de l’ordinateur portable.
9. Hygiène des données lors de la migration
La partie la plus délicate du transfert vers le serveur n’est pas la technique, mais la question de ce qu’il faut emporter. Trois règles :
- Aucune clé privée sur le serveur.
authorized_keysne contient que des clés publiques. Les clés privées restent sur les appareils terminaux. - Ne pas copier les données d’accès sans distinction. Les fichiers locaux sensibles tels qu’un
.credentials.jsonne doivent pas être transférés sans vérification sur le VPS. Il faut plutôt s’authentifier à nouveau sur le serveur. - Placer d’abord la configuration dans un dossier de migration. Ne pas écrire directement les mémoires et configurations Claude existantes dans les chemins de configuration actifs, mais les transférer d’abord dans un dossier de migration séparé et y vérifier ce qui doit réellement être repris. Ce qui n’est plus nécessaire, comme d’anciennes entrées MCP ou des paramètres orphelins, est délibérément laissé de côté plutôt que déplacé sans examen.
10. Aperçus web via un tunnel SSH
Pour les aperçus web, par exemple un serveur de développement local démarré par Claude, la tentation est grande d’ouvrir simplement un port supplémentaire. Il ne faut pas le faire. Chaque port ouvert supplémentaire augmente la surface d’attaque. À la place, l’aperçu passe par un tunnel de port SSH chiffré : le service écoute uniquement localement sur le serveur, et SSH le transmet au client.
Depuis le PC, rendre accessible un service exécuté localement sur le port 4321 :
ssh -p 61417 -L 4321:localhost:4321 claude@SERVER
Ouvrir ensuite http://localhost:4321 dans le navigateur local. Le trafic passe intégralement par la connexion SSH existante et authentifiée, sans devoir ouvrir le moindre port supplémentaire dans le pare-feu.
Accès depuis l’iPhone
L’accès en déplacement fonctionne selon le même modèle de sécurité que depuis le PC. Il suffit d’un client SSH avec gestion des clés. Termius, Blink Shell et Secure ShellFish sont répandus ; tous peuvent générer des clés Ed25519 et les stocker dans le trousseau iOS, parfois protégées par Face ID.
La procédure correspond à l’étape 3, mais sur l’iPhone :
- Générer dans le client SSH une clé Ed25519 dédiée à l’iPhone, sans copier la clé du PC. La clé privée reste dans le trousseau de l’appareil.
- Ajouter la clé publique de l’iPhone comme ligne supplémentaire dans
~/.ssh/authorized_keyssur le serveur, avec un commentaire explicite (iphone-15). - Créer la connexion dans le client : adresse du serveur, utilisateur
claude, port61417, clé de l’iPhone pour l’authentification.
C’est précisément pourquoi une clé distincte par appareil est utile : si l’iPhone est perdu, il suffit de supprimer du serveur la ligne iphone-15 de authorized_keys, et l’appareil est exclu tandis que l’accès PC et toutes les autres clés continuent de fonctionner sans changement.
Après la connexion, récupérer la session Claude en cours avec tmux attach -t claude et reprendre là où l’on s’était arrêté à son bureau. Le tunnel de port de l’étape 10 fonctionne également depuis iOS ; Termius et Secure ShellFish prennent en charge la redirection de port.
Checklist
Voici le déroulement complet en résumé :
- Debian 13 installé et entièrement mis à jour avec
apt full-upgrade. - Utilisateur dédié
claudeavec droits sudo ; connexion root directe désormais inutilisée. - Clés Ed25519 protégées par phrase secrète, une par appareil ; uniquement des clés publiques dans
authorized_keys. - sshd renforcé :
PermitRootLogin no,PasswordAuthentication no; vérifié avecsshd -tavant rechargement, session existante laissée ouverte jusqu’au test. - SSH sur le port 61417, défini sur
ssh.socketen cas d’activation par socket, sinon dans la configuration sshd. - Pare-feu du fournisseur : DROP entrant par défaut, seule exception TCP 61417 ; trafic sortant autorisé.
- Surface d’attaque vérifiée avec
ss -lntup(seul SSH est public,chronydest local) etsystemctl --failed(aucune erreur). - Claude Code authentifié à nouveau sur le serveur, exploité dans une session
tmux. - Hygiène des données : aucune clé privée ni donnée d’accès sur le serveur, configuration d’abord vérifiée via un dossier de migration.
- Aucun port supplémentaire ; les aperçus web passent par un tunnel SSH.
Après cette configuration, seul SSH est accessible depuis l’extérieur sur le port défini, et exclusivement avec une clé protégée par phrase secrète. Claude Code fonctionne indépendamment de l’appareil terminal dans tmux ; les aperçus web restent accessibles via des tunnels SSH, sans ouvrir de port supplémentaire.

Commentaires
Les commentaires sont chargés depuis GitHub / Giscus.