Offre Durée limitée : -10% sur tout le site* avec le code ELYPSEWELCOME10

Installer DeepSeek Harness (dsh) sur un VPS Linux : un agent de code open source accessible depuis le navigateur

Mis à jour le 11 novembre 2026 22 min de lecture 15 sections

DeepSeek Harness (dsh) : un agent de code open source piloté depuis le navigateur

DeepSeek Harness, abrégé dsh du nom de sa commande, est un « harnais » d'agents IA open source publié par DeepSeek AI sur GitHub, dans le dépôt deepseek-ai/deepseek-harness. Écrit en TypeScript et distribué sous licence MIT, il repose sur une architecture où tout est plugin, bâtie sur le framework Cordis. Créé le 13 août 2026, le dépôt dépasse 278 000 étoiles et 34 000 forks au 11 novembre 2026. Le harnais relie un modèle de langage (LLM) à des outils : l'agent peut lire et modifier des fichiers, exécuter des commandes shell, déléguer des tâches et tenir un plan, en demandant une approbation pour les opérations soumises à la politique de permissions active.

dsh se pilote de plusieurs façons : une interface web servie par la commande dsh web, un mode headless qui exécute une tâche puis rend la main, et des modes ACP et SDK, qui dialoguent sur l'entrée et la sortie standard, pour brancher d'autres clients. C'est l'interface web qui nous intéresse ici : installée sur un VPS Linux allumé en permanence, elle donne un agent de code joignable depuis n'importe quel navigateur, y compris celui d'un téléphone, qui travaille directement sur les fichiers et les dépôts Git du serveur.

Le projet se présente lui-même comme une préversion pour développeurs (developer preview) : des changements incompatibles sont annoncés entre versions, et sa notice de sécurité (SAFETY.md) précise qu'il n'a fait l'objet d'aucun audit de sécurité. Ce tutoriel en tient compte à chaque étape : Node.js 24 installé avec NVM, dsh web lancé en service systemd sous un utilisateur dédié, publication derrière Nginx en HTTPS avec authentification, configuration des fournisseurs de modèles (DeepSeek, Anthropic, OpenAI ou Ollama en local), puis bac à sable et règles d'exposition.

Ce que change la version 0.2.2-rc.1 du 4 novembre 2026

La dernière version, la 0.2.2-rc.1, a été publiée le 4 novembre 2026. Marquée comme préversion (pre-release) sur GitHub, c'est aussi celle que le registre npm sert sous l'étiquette latest du paquet @deepseek-ai/dsh. Pour un administrateur de serveur, cinq changements comptent :

  • Node.js 24.9 minimum : le champ engines passe de ^22.19.0 || >=24.0.0 (version 0.2.1-rc.5) à >=24.9.0. Un VPS resté sous Node.js 22 doit d'abord changer de version ;
  • Téléphones et tablettes : meilleure gestion du clavier virtuel, de la navigation et des mises en page étroites, avec des menus et des actions qui restent accessibles sur petit écran ;
  • Web Fetch accepte les adresses non publiques : l'outil de récupération web de l'agent n'interdit plus les adresses locales et privées, pour permettre les usages derrière un proxy ou sur un réseau interne. Les notes de version précisent qu'il revient au déployeur de restreindre lui-même l'accès réseau ;
  • Permissions conservées à l'arrêt : les permissions Auto enregistrées et la politique d'approbation sont conservées quand l'application s'arrête, au lieu de basculer en accès complet ;
  • Délégation expérimentale : un nouveau plugin expérimental, subagent_oar, peut confier des tâches indépendantes à la CLI Codex ou à la CLI Claude installées sur la machine.

Le changement sur Web Fetch est celui qui pèse le plus sur un serveur partagé : tout service qui écoute en local sans authentification (API Ollama, Redis, console d'administration d'un serveur de jeu) devient joignable par l'agent. Nous y revenons dans la partie sécurité.

Prérequis : quel VPS Linux pour DeepSeek Harness

  • Un VPS Linux sous Debian 12 ou 13, ou Ubuntu 24.04 ou 26.04 LTS, avec un accès SSH par clé (sécuriser SSH sur un VPS Linux) ;
  • Un nom de domaine ou un sous-domaine (dsh.example.fr dans ce guide) dont l'enregistrement DNS A pointe vers l'adresse IP du VPS, pour le certificat Let's Encrypt ;
  • Nginx et Certbot, installés depuis les paquets de la distribution ;
  • Une clé API DeepSeek, Anthropic ou OpenAI, ou un serveur Ollama déjà installé sur le VPS (installer Ollama sur un VPS Linux) ;
  • Git, utile à l'agent pour versionner les projets, et bubblewrap pour le bac à sable des commandes.

Côté ressources, la documentation de dsh ne publie pas de configuration minimale. Avec un fournisseur en API (DeepSeek, Anthropic, OpenAI), l'inférence se fait chez le fournisseur : le VPS n'héberge que le processus Node.js de dsh, les fichiers de travail et les commandes lancées par l'agent (compilation, tests, installation de dépendances). Avec Ollama en local, c'est le modèle qui dimensionne la machine : ses poids en RAM, plus le cache du contexte, et un agent de code envoie au modèle de longs échanges (fichiers lus, sorties de commandes). Avant de télécharger un modèle, faites le calcul avec llmfit.

Une règle avant tout : installez dsh sur un VPS consacré à cet usage, pas sur celui qui fait tourner votre serveur FiveM, Minecraft ou votre panel de jeu. Un agent qui exécute des commandes et peut joindre les adresses locales n'a rien à faire à côté d'une base MySQL de production ou de l'API d'un panel.

Étape 1 : préparer le VPS et créer un utilisateur dédié

dsh exécute les commandes proposées par le modèle avec les droits du compte qui le lance. Ce compte ne doit être ni root ni membre du groupe sudo. Installez les paquets nécessaires, puis créez un utilisateur système dédié, sans mot de passe, et un répertoire de projets qui servira d'espace de travail (workspace) :

sudo apt update
sudo apt install -y git curl bubblewrap nginx certbot apache2-utils
sudo adduser --disabled-password --gecos "" dsh
sudo chmod 700 /home/dsh
sudo -u dsh mkdir -p /home/dsh/projets
sudo -l -U dsh

Le paquet bubblewrap fournit bwrap, le premier mécanisme de bac à sable que dsh essaie sous Linux. apache2-utils fournit htpasswd, qui servira à l'authentification Nginx. La dernière commande doit répondre que l'utilisateur dsh n'est pas autorisé à utiliser sudo : c'est le résultat attendu.

Étape 2 : installer Node.js 24 avec NVM

dsh 0.2.2 exige Node.js 24.9 ou plus récent. Les dépôts des distributions n'y sont pas : le paquet nodejs est en version 18 sur Debian 12 et Ubuntu 24.04, 20 sur Debian 13 et 22 sur Ubuntu 26.04 LTS. NVM (Node Version Manager) installe Node.js dans le répertoire personnel de l'utilisateur, sans droits root, et permet de changer de version en une commande. La méthode complète est détaillée dans notre guide installer et sécuriser Node.js avec NVM ; voici l'essentiel, à exécuter sous l'utilisateur dsh :

sudo -iu dsh
curl -fsSLo nvm-install.sh https://raw.githubusercontent.com/nvm-sh/nvm/v0.41.0/install.sh
less nvm-install.sh
bash nvm-install.sh
source ~/.bashrc
nvm install 24
nvm alias default 24
node --version
nvm which 24

node --version doit afficher v24.9.0 ou plus : la branche LTS 24 est en v24.22.2 au 11 novembre 2026. Notez le chemin renvoyé par nvm which 24, par exemple /home/dsh/.nvm/versions/node/v24.22.2/bin/node : le service systemd en aura besoin, car il ne charge pas le profil shell dans lequel NVM s'initialise. Node.js 26, l'autre branche LTS, respecte aussi la contrainte >=24.9.0 déclarée par le paquet.

Étape 3 : installer dsh et le tester par un tunnel SSH

Le README propose de lancer dsh sans installation, avec npx @deepseek-ai/dsh web. Sur un serveur, une installation globale dans l'environnement NVM de l'utilisateur dsh est préférable : le service démarre sans téléchargement, et la version ne change que lorsque vous le décidez. Toujours sous l'utilisateur dsh :

npm install -g @deepseek-ai/dsh@0.2.2-rc.1
dsh --version

L'étiquette npm latest pointe déjà sur 0.2.2-rc.1, mais épingler la version évite une mise à jour involontaire vers une préversion qui modifierait la configuration. Premier lancement :

cd ~/projets
dsh --profile web --no-open

dsh web est le raccourci de dsh --profile web. Au démarrage, une ligne qui commence par dsh web: affiche l'URL de l'interface, de la forme http://127.0.0.1:3080/ suivie d'un jeton de lancement. Ce jeton est généré à chaque démarrage du processus : le navigateur l'échange contre un cookie de session signé, puis est redirigé vers une adresse sans jeton. Par défaut, dsh écoute sur le port 3080 de la boucle locale (loopback) : rien n'est joignable depuis Internet. Pour tester depuis votre poste, ouvrez un tunnel SSH dans un second terminal :

ssh -N -L 3080:127.0.0.1:3080 admin@IP_DU_VPS

Collez ensuite l'URL complète affichée par dsh dans le navigateur de votre poste. Dans Settings puis Models, enregistrez une clé de fournisseur (voir plus bas), puis cliquez sur Choose workspace pour ajouter /home/dsh/projets : tant qu'aucun espace de travail n'est sélectionné, la zone de saisie de session reste inactive. Arrêtez dsh avec Ctrl+C une fois le test concluant.

Pour un administrateur seul, le tunnel SSH suffit : si personne d'autre n'a besoin de l'interface, vous pouvez vous arrêter après l'étape systemd et ne jamais publier dsh sur Internet.

Étape 4 : lancer dsh web en service systemd

Pour que dsh démarre avec le VPS et redémarre après un plantage, créez une unité systemd (créer un service systemd sous Linux). Revenez à votre compte d'administration (exit), puis remplacez dans le fichier la version de Node.js par celle de nvm which 24 et dsh.example.fr par votre domaine :

sudo nano /etc/systemd/system/dsh-web.service
[Unit]
Description=DeepSeek Harness (dsh web)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=dsh
Group=dsh
WorkingDirectory=/home/dsh/projets
Environment=DSH_HOME=/home/dsh/.dsh
Environment=PATH=/home/dsh/.nvm/versions/node/v24.22.2/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=/home/dsh/.nvm/versions/node/v24.22.2/bin/dsh --profile web --no-open --host 127.0.0.1 --port 3080 --public-url https://dsh.example.fr/ --trusted-host dsh.example.fr
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Ce que fait chaque réglage :

  • WorkingDirectory : dsh travaille par défaut dans le répertoire depuis lequel il est lancé ;
  • Environment=PATH : l'exécutable dsh est un script Node.js, il faut que le répertoire de Node.js installé par NVM figure dans le PATH du service ;
  • DSH_HOME : le répertoire de données de dsh, ~/.dsh par défaut. Il contient les profils, la configuration et le fichier .credentials.yaml où sont stockées les clés API. Le fixer explicitement évite toute ambiguïté ;
  • --host 127.0.0.1 --port 3080 : écoute locale uniquement. dsh refuse les adresses joker comme 0.0.0.0 : --host n'accepte qu'une adresse IP concrète d'une interface locale ;
  • --public-url : l'adresse publique affichée dans la ligne dsh web: et transmise à l'agent. Elle n'accorde aucune confiance et ne configure aucune écoute ;
  • --trusted-host : ajoute le nom de domaine aux autorités acceptées par le contrôle Host/Origin de l'API. Sans lui, les appels à l'API reçoivent une erreur 403 derrière le proxy ;
  • NoNewPrivileges=true : aucun processus lancé par l'agent ne peut gagner de privilèges via sudo ou un binaire setuid.

Activez le service, vérifiez l'écoute et récupérez l'URL de connexion :

sudo systemctl daemon-reload
sudo systemctl enable --now dsh-web
systemctl status dsh-web
sudo ss -ltnp | grep 3080
sudo journalctl -u dsh-web -n 50 --no-pager | grep "dsh web:"

ss doit montrer 127.0.0.1:3080 et rien d'autre (lister les ports en écoute avec ss). La dernière commande retrouve l'URL avec jeton, qui pointe désormais vers https://dsh.example.fr/. Chaque redémarrage du service génère un nouveau jeton : relisez le journal après un systemctl restart. Cette URL est un identifiant : quiconque lit le journal système (root et les membres des groupes adm et systemd-journal) peut ouvrir une session. N'ajoutez personne à ces groupes à la légère.

Étape 5 : publier dsh derrière Nginx en HTTPS avec authentification

La documentation de dsh liste ce que le reverse proxy doit faire : conserver l'en-tête Host tel que le navigateur l'a envoyé, transmettre les connexions WebSocket avec leurs en-têtes Upgrade et Connection, et ajouter l'attribut Secure aux cookies sur la branche HTTPS quand dsh lui-même sert en HTTP. Publier dsh à la racine d'un sous-domaine évite les réécritures supplémentaires (retrait du préfixe, chemin des cookies) qu'impose un montage sous un chemin comme /ui/. Les bases du reverse proxy sont expliquées dans notre guide Nginx en reverse proxy sur un VPS Linux.

a. Obtenir le certificat. Créez d'abord un bloc qui ne sert, en HTTP, que les défis Let's Encrypt et redirige tout le reste vers HTTPS :

sudo nano /etc/nginx/sites-available/dsh
server {
    listen 80;
    listen [::]:80;
    server_name dsh.example.fr;

    location /.well-known/acme-challenge/ { root /var/www/html; }
    location / { return 301 https://$host$request_uri; }
}
sudo ln -s /etc/nginx/sites-available/dsh /etc/nginx/sites-enabled/dsh
sudo nginx -t && sudo systemctl reload nginx
sudo certbot certonly --webroot -w /var/www/html -d dsh.example.fr --deploy-hook "systemctl reload nginx"

La méthode webroot laisse le chemin /.well-known/acme-challenge/ accessible en HTTP : le renouvellement automatique fonctionne sans toucher à la configuration, et le crochet --deploy-hook recharge Nginx après chaque renouvellement (Certbot et Let's Encrypt sur un VPS Linux).

b. Créer le compte d'accès. L'authentification HTTP de Nginx ajoute un premier verrou devant celui de dsh :

sudo htpasswd -c /etc/nginx/.htpasswd-dsh admin
sudo chown root:www-data /etc/nginx/.htpasswd-dsh
sudo chmod 640 /etc/nginx/.htpasswd-dsh

c. Ajouter le bloc HTTPS à la suite du même fichier :

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name dsh.example.fr;

    ssl_certificate     /etc/letsencrypt/live/dsh.example.fr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/dsh.example.fr/privkey.pem;

    auth_basic           "DeepSeek Harness";
    auth_basic_user_file /etc/nginx/.htpasswd-dsh;

    access_log /var/log/nginx/dsh.access.log;
    error_log  /var/log/nginx/dsh.error.log;

    location / {
        proxy_pass http://127.0.0.1:3080;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_cookie_flags ~ secure;
        proxy_read_timeout 1h;
        proxy_send_timeout 1h;
    }
}

Quelques précisions sur ce bloc :

  • le bloc map convertit l'en-tête Upgrade du navigateur en Connection: upgrade, indispensable au WebSocket. Si un autre site du serveur définit déjà $connection_upgrade, supprimez ce doublon, sinon nginx -t échoue ;
  • proxy_set_header Host $host transmet le nom de domaine reçu, celui que --trusted-host autorise côté dsh ;
  • proxy_cookie_flags ~ secure ajoute l'attribut Secure à tous les cookies renvoyés par dsh, dont le cookie de session. La directive existe depuis Nginx 1.19.3 ;
  • proxy_read_timeout 1h : par défaut, Nginx ferme une connexion proxifiée qui ne transmet rien pendant 60 secondes, ce qui couperait le WebSocket d'une session inactive.

d. Activer et fermer le reste. Testez, rechargez, et n'ouvrez dans le pare-feu que SSH, HTTP et HTTPS (ouvrir des ports avec UFW). Le port 3080 ne doit jamais apparaître dans les règles :

sudo nginx -t && sudo systemctl reload nginx
sudo ufw allow OpenSSH
sudo ufw allow "Nginx Full"
sudo ufw enable
sudo ufw status

Ouvrez enfin l'URL relevée dans le journal (https://dsh.example.fr/ suivie du jeton) : Nginx demande d'abord l'identifiant admin, puis dsh échange le jeton contre son cookie de session. Pour bloquer les essais de mot de passe en série, activez la prison nginx-http-auth de Fail2ban sur le journal d'erreurs du site (configurer Fail2ban) :

[nginx-http-auth]
enabled  = true
port     = http,https
logpath  = /var/log/nginx/dsh.error.log

Ces lignes vont dans /etc/fail2ban/jail.local, suivies d'un sudo systemctl restart fail2ban.

Tunnel SSH, VPN ou HTTPS : comparatif des modes d'accès

Publier l'interface sur Internet n'est pas une obligation. Le bon choix dépend du nombre de personnes qui utilisent l'agent et des appareils depuis lesquels elles s'y connectent :

Mode d'accèsCe qui est exposé sur InternetAuthentificationUsage conseillé
Tunnel SSH (ssh -L)Le port SSH, déjà ouvertClé SSH, puis jeton dshAdministrateur seul, depuis un ordinateur
VPN WireGuardUn port UDPClé WireGuard, puis jeton dshPetite équipe, téléphone compris
Nginx HTTPS + authentificationLes ports 80 et 443Mot de passe Nginx, puis jeton et cookie signé dshAccès depuis n'importe quel navigateur
--host sur l'IP publique, sans TLSLe port 3080 en HTTP clairJeton seul, lisible sur le réseauJamais

Le VPN combine les avantages des deux premières lignes : l'interface reste invisible depuis Internet tout en restant joignable depuis un téléphone (installer WireGuard sur un VPS Linux). La dernière ligne correspond au cas où dsh écoute hors de la boucle locale sans certificat : il sert alors en HTTP clair et affiche lui-même un avertissement au démarrage.

Étape 6 : configurer les fournisseurs de modèles

Toute la configuration des modèles passe par Settings puis Models, et s'applique sans redémarrer le service. Les clés saisies sont stockées dans $DSH_HOME/.credentials.yaml (ici /home/dsh/.dsh/.credentials.yaml) : les paramètres ne conservent qu'une référence. La configuration avancée du profil web se trouve dans $DSH_HOME/profiles/web/cordis.patch.yml, relu à la requête suivante.

Clé API DeepSeek

DeepSeek dispose d'une carte dédiée avec un seul champ : la clé API, créée sur la plateforme développeur de DeepSeek (platform.deepseek.com). La liste des modèles suit celle que publie l'API DeepSeek, avec repli sur les modèles intégrés à dsh. Le niveau de raisonnement par défaut se règle dans le fichier de profil :

- id: llm-deepseek
  config:
    reasoningEffort: max

Clés Anthropic et OpenAI

Cliquez sur Add model provider, choisissez Third-party model provider, puis le fournisseur du catalogue : anthropic pour les modèles Claude, openai pour ceux d'OpenAI. Le catalogue propose aussi moonshotai (Kimi) et zai (GLM). Le catalogue fournit l'adresse de l'API, le protocole et la liste des modèles : il ne reste qu'à saisir la clé. Laissé vide, le champ se rabat sur des identifiants déjà enregistrés ou sur une variable d'environnement détectée (indicateur vert si une variable est trouvée, jaune sinon). Cette détection ne valide ni la clé ni la connexion : envoyez un premier message pour vérifier.

Ollama local, sans clé externe

Ollama n'est pas dans le catalogue : il se déclare comme Custom model API, car il expose une API compatible OpenAI sur /v1. Ollama écoute par défaut sur 127.0.0.1:11434, sur le même VPS que dsh. Renseignez :

  • identifiant du fournisseur : ollama (il est définitif) ;
  • nom affiché : par exemple « Ollama local » ;
  • base URL : http://127.0.0.1:11434/v1 ;
  • protocole : openai-completions (OpenAI Chat Completions) ;
  • clé : une valeur quelconque, par exemple ollama. La documentation d'Ollama précise que les clients exigent une valeur, mais qu'Ollama l'ignore ;
  • modèles : cliquez sur Fetch available models, qui interroge /models sur l'adresse indiquée et liste les modèles déjà téléchargés.

Un agent de code repose sur l'appel d'outils (tool calling) : choisissez un modèle qui le prend en charge, repérable avec le filtre Tools de la bibliothèque Ollama, et vérifiez la longueur de contexte configurée côté Ollama (OLLAMA_CONTEXT_LENGTH), car l'agent remplit vite une fenêtre courte (gérer ses modèles Ollama). Avec Ollama, aucune requête ne quitte le VPS : ni le code, ni les fichiers lus par l'agent.

FournisseurOù le déclarerCe qu'il faut saisirOù partent les requêtes
DeepSeekCarte DeepSeek de Settings, ModelsClé API DeepSeekAPI DeepSeek
Anthropic (Claude)Third-party model provider, anthropicClé API AnthropicAPI Anthropic
OpenAIThird-party model provider, openaiClé API OpenAIAPI OpenAI
Ollama localCustom model API, protocole openai-completionsBase URL http://127.0.0.1:11434/v1, clé quelconqueLe VPS lui-même

Pour chaque fournisseur en ligne, créez une clé réservée à ce serveur : en cas de doute, vous la révoquez sans couper vos autres usages.

Le bac à sable des outils : ce qu'il protège, et ce qu'il ne protège pas

Avant chaque appel d'outil, dsh fait passer la demande par une chaîne de contrôles (crochets, permissions, bac à sable) qui aboutit à trois décisions possibles : autoriser, refuser, ou demander. Une demande ouvre une invite d'approbation à usage unique dans l'interface ; si l'approbation ne peut pas être obtenue, l'appel est refusé par défaut. Le bac à sable lui-même connaît trois modes, proposés dans l'interface web sous forme de préréglages :

Mode du bac à sablePréréglage de l'interfaceEffet sur les fichiersUsage conseillé sur un VPS
read-onlyRead OnlyLes commandes confinées ne peuvent modifier aucun fichierAudit, lecture de journaux, questions sur un projet
workspace-writeWorkspace WriteÉcriture permise dans l'espace de travail et un /tmp éphémèreTravail courant sur un dépôt
danger-full-accessFull accessAucune restriction sur les modifications de fichiersÀ éviter sur un serveur qui héberge autre chose

Le préréglage Full access demande une confirmation de risque. Un quatrième préréglage, Auto review, n'apparaît que si l'intégration expérimentale correspondante est chargée explicitement. Côté configuration, le README du paquet @deepseek-ai/dsh-sandbox-policy documente trois clés : le mode par défaut des sessions (read-only si rien n'est précisé), la racine de l'espace de travail (un chemin absolu) et d'éventuels répertoires supplémentaires accessibles en écriture :

- name: '@deepseek-ai/dsh-sandbox-policy'
  config:
    mode: workspace-write
    workspaceRoot: /home/dsh/projets
    additionalWritableRoots: []

N'ajoutez pas le répertoire Git complet d'un worktree à additionalWritableRoots : la documentation du paquet prévient qu'il permet de modifier des hooks ou une configuration Git susceptibles de s'exécuter hors du bac à sable.

Sous Linux, deux mécanismes de confinement sont essayés dans l'ordre : bubblewrap (bwrap), puis Landlock, le module de sécurité du noyau. Le profil bwrap monte la racine du système en lecture seule, fournit un /dev neuf et un /proc issu d'un espace de noms PID privé : les commandes ne voient pas les processus de l'hôte. En mode workspace-write, seuls l'espace de travail, un /tmp éphémère et les répertoires supplémentaires déclarés sont montés en écriture. Landlock peut n'offrir qu'une couverture partielle selon la version du noyau. Si aucun des deux ne fonctionne, la commande échoue avec l'erreur SANDBOX_UNAVAILABLE au lieu de s'exécuter sans confinement. Le choix du mécanisme est mis en cache : après avoir installé ou réparé bubblewrap, redémarrez le service.

Ce que le bac à sable ne couvre pas : ses modes ne régissent que les effets sur les fichiers. Le réseau et les processus sortent de son périmètre, et la notice SAFETY.md rappelle que le bac à sable, les approbations et les contrôles de permissions réduisent les risques sans garantir l'isolation. Même correctement appliqués, ils ne protègent pas ce à quoi dsh a légitimement accès : les fichiers de l'utilisateur dsh, ses clés API, les services réseau qu'il peut joindre. D'où l'utilisateur dédié, sans sudo, sur un VPS séparé.

Ne jamais exposer l'agent sans authentification : les leçons de l'incident WorkOS

L'actualité de novembre 2026 illustre le risque. Dans son bulletin de sécurité mis à jour le 6 novembre, le fournisseur d'authentification WorkOS explique qu'un agent de sécurité IA, lancé par un chercheur qui évaluait des outils avec ARTEX, est sorti du bac à sable de ce chercheur et a atteint un outil interne de l'entreprise. Quatre défauts se sont enchaînés : l'API de l'outil était joignable depuis Internet, elle acceptait un identifiant prévu pour le développement local et déployé aussi en production, aucune limitation de débit n'a freiné l'extraction des données, et l'activité, commencée le 25 octobre, n'a été détectée que le 30. Seules les données des systèmes commerciaux et du support client ont été touchées, et le chercheur a confirmé les avoir supprimées.

La leçon vaut dans les deux sens pour un agent de code auto-hébergé. Un dsh exposé sans authentification, c'est un terminal offert à quiconque trouve l'adresse, y compris à des agents qui parcourent Internet à la recherche d'API ouvertes. Et un agent qui sort de son cadre peut atteindre ce qui l'entoure, d'autant plus que Web Fetch accepte les adresses locales depuis la 0.2.2-rc.1. La liste de contrôle :

  • Écoute locale uniquement : --host 127.0.0.1, jamais de règle de pare-feu sur le port 3080, vérification régulière avec ss -ltnp ;
  • Deux verrous : authentification Nginx ou VPN devant, jeton et cookie signé de dsh derrière. Le jeton seul ne suffit pas : une URL copiée dans un ticket, un salon Discord ou une capture d'écran donne l'accès ;
  • Pas d'identifiant faible : mot de passe Nginx long et unique, aucun compte de test oublié dans .htpasswd-dsh ;
  • Limiter les essais : Fail2ban sur l'authentification Nginx, là où WorkOS n'avait aucune limitation de débit ;
  • Révoquer vite : sudo systemctl restart dsh-web invalide le jeton en cours ; supprimer la clé chez le fournisseur coupe l'accès au modèle ;
  • Moindre privilège : utilisateur dédié sans sudo, NoNewPrivileges, VPS séparé des serveurs de jeu, des bases de données et des panels, dont les API locales seraient sinon joignables par l'agent ;
  • Détecter : relisez /var/log/nginx/dsh.access.log et journalctl -u dsh-web, à la recherche de connexions inattendues ou de connexions depuis des adresses inconnues ;
  • Sauvegarder : SAFETY.md recommande de garder des sauvegardes des fichiers accessibles au projet. Une copie régulière de /home/dsh/projets et de /home/dsh/.dsh hors du VPS suffit (sauvegarder un VPS avec rsync) ;
  • Relire les plugins : SAFETY.md demande d'examiner les plugins, la configuration et les commandes proposées avant de les autoriser. Un plugin tiers s'exécute avec les droits de dsh.

Mettre à jour dsh et Node.js sans casser le service

Le projet est en préversion : lisez les notes de la version visée sur GitHub avant de mettre à jour, et sauvegardez /home/dsh/.dsh. Les étiquettes npm indiquent ce qui est publié (latest, next, alpha) :

sudo -iu dsh
npm view @deepseek-ai/dsh dist-tags
npm install -g @deepseek-ai/dsh@VERSION_VISEE
exit
sudo systemctl restart dsh-web
sudo journalctl -u dsh-web -n 50 --no-pager | grep "dsh web:"

Si vous changez de version de Node.js avec NVM, le chemin du binaire change aussi : les paquets globaux sont installés par version de Node.js, donc réinstallez dsh dans la nouvelle version, puis mettez à jour Environment=PATH et ExecStart dans l'unité, suivis d'un sudo systemctl daemon-reload et d'un redémarrage.

Dépannage : les erreurs courantes

SymptômeCause probableCorrection
npm affiche EBADENGINE à l'installation, ou dsh échoue au démarrageNode.js plus ancien que 24.9nvm install 24, puis réinstaller dsh
Le service échoue avec status=203/EXECChemin de ExecStart fauxReprendre le chemin de nvm which 24
Refus au démarrage avec --host 0.0.0.0Les adresses joker sont refuséesGarder 127.0.0.1 et passer par Nginx
Les appels à l'API répondent 403 derrière Nginx--trusted-host absent ou différent du domaineAligner --trusted-host sur server_name
L'interface s'affiche mais la session ne répond pasEn-têtes WebSocket non transmisVérifier Upgrade, Connection et le bloc map
Le lien enregistré ne fonctionne plusNouveau jeton après un redémarrageRelire la ligne dsh web: dans le journal
Les commandes échouent avec SANDBOX_UNAVAILABLENi bwrap ni Landlock utilisablesInstaller bubblewrap, vérifier le noyau, redémarrer le service
Impossible d'écrire un messageAucun espace de travail choisiChoose workspace, puis sélectionner le répertoire

Conclusion : un agent de code utile, à condition de le cloisonner

DeepSeek Harness s'installe en quelques commandes sur un VPS Linux : Node.js 24 avec NVM, npm install -g @deepseek-ai/dsh, une unité systemd et un bloc Nginx. Le résultat est un agent de code open source, accessible depuis un navigateur ou un téléphone, qui peut s'appuyer sur DeepSeek, Claude, OpenAI ou un modèle Ollama hébergé sur la même machine. Le travail d'administrateur se situe ailleurs : garder l'écoute en local, mettre deux verrous devant l'interface, choisir le bon mode de bac à sable, et séparer l'agent de tout ce qui compte en production. Si l'agent doit faire tourner des modèles locaux plus lourds, un serveur dédié offre la RAM qu'un petit VPS n'a pas.

FAQ

Qu'est-ce que DeepSeek Harness (dsh) ?

DeepSeek Harness est un harnais d'agents IA open source publié par DeepSeek AI sur GitHub (dépôt deepseek-ai/deepseek-harness), écrit en TypeScript sur une architecture où tout est plugin. Sa commande, dsh, relie un modèle de langage à des outils : l'agent lit et modifie des fichiers, exécute des commandes, délègue des tâches et tient un plan, avec des demandes d'approbation. Il se pilote par une interface web (dsh web), en mode headless ou par les modes ACP et SDK.

DeepSeek Harness est-il gratuit et open source ?

Oui. Le code est publié sous licence MIT et le paquet npm @deepseek-ai/dsh est gratuit. Les appels aux modèles se paient chez le fournisseur choisi (DeepSeek, Anthropic, OpenAI) selon sa propre tarification. Avec un modèle Ollama hébergé sur votre VPS ou votre serveur dédié, il n'y a aucun frais d'API : seule la machine travaille.

Quelle version de Node.js faut-il pour DeepSeek Harness ?

Node.js 24.9 ou plus récent depuis la version 0.2.2-rc.1 du 4 novembre 2026 : le champ engines vaut >=24.9.0, contre ^22.19.0 || >=24.0.0 en 0.2.1-rc.5. Les paquets nodejs de Debian 12 et 13 et d'Ubuntu 24.04 et 26.04 sont plus anciens : installez Node.js 24 avec NVM (nvm install 24), sous l'utilisateur qui fera tourner dsh.

Comment installer DeepSeek Harness sur un VPS Linux ?

Sous un utilisateur dédié sans sudo, installez Node.js 24 avec NVM, puis npm install -g @deepseek-ai/dsh@0.2.2-rc.1. Testez avec dsh --profile web --no-open et un tunnel SSH (ssh -L 3080:127.0.0.1:3080), puis créez une unité systemd qui lance dsh avec --host 127.0.0.1, --port 3080, --public-url et --trusted-host, et publiez-la derrière Nginx en HTTPS avec authentification.

Sur quel port écoute l'interface web de dsh ?

Sur le port 3080 de la boucle locale (127.0.0.1) par défaut, ce qui la rend injoignable depuis Internet. L'option --port change le port, --host accepte une seule adresse IP concrète d'une interface locale : les adresses joker comme 0.0.0.0 sont refusées au démarrage. Pour un accès distant, passez par un tunnel SSH, un VPN ou un reverse proxy Nginx en HTTPS.

Peut-on utiliser DeepSeek Harness avec Claude ou les modèles OpenAI ?

Oui. Dans Settings puis Models, cliquez sur Add model provider, choisissez Third-party model provider, puis anthropic pour Claude ou openai pour OpenAI, et saisissez la clé API. Le catalogue fournit l'adresse, le protocole et la liste des modèles. DeepSeek a sa propre carte avec un seul champ de clé, et le catalogue propose aussi moonshotai (Kimi) et zai (GLM).

Comment brancher dsh sur un Ollama installé sur le même VPS ?

Ajoutez un fournisseur de type Custom model API avec l'identifiant ollama, la base URL http://127.0.0.1:11434/v1 et le protocole openai-completions. Saisissez une clé quelconque, car Ollama l'ignore, puis cliquez sur Fetch available models pour lister les modèles téléchargés. Choisissez un modèle qui gère l'appel d'outils (filtre Tools de la bibliothèque Ollama) et une longueur de contexte suffisante.

Comment fonctionne l'authentification de l'interface web dsh ?

Au démarrage, dsh affiche une ligne dsh web: avec une URL qui contient un jeton de lancement, renouvelé à chaque démarrage. Le navigateur échange ce jeton contre un cookie de session signé, qui authentifie ensuite chaque appel à l'API et chaque flux WebSocket. dsh ne propose pas de compte ni de mot de passe : sur Internet, ajoutez une authentification Nginx ou un VPN devant.

Le bac à sable de dsh suffit-il à protéger le serveur ?

Non. Sous Linux, dsh confine les commandes avec bubblewrap, ou Landlock à défaut, selon trois modes : read-only, workspace-write et danger-full-access. Ces modes ne régissent que les effets sur les fichiers : le réseau et les processus sortent de leur périmètre. La notice SAFETY.md précise que le projet n'a pas été audité et ne doit pas être le seul contrôle de sécurité.

Peut-on installer dsh sur le VPS de son serveur FiveM ou Minecraft ?

C'est déconseillé. dsh exécute des commandes proposées par un modèle, et depuis la version 0.2.2-rc.1 son outil Web Fetch accepte les adresses locales et privées : une base MySQL, l'API d'un panel ou la console d'un serveur de jeu qui écoutent en local deviendraient joignables par l'agent. Un VPS séparé, consacré à l'agent, limite les dégâts en cas d'erreur.

Quel est le rapport entre dsh et l'incident WorkOS ?

Aucun lien technique : WorkOS a expliqué le 6 novembre 2026 qu'un agent de sécurité IA, sorti du bac à sable d'un chercheur, avait atteint une API interne exposée sur Internet, avec un identifiant de développement accepté en production et sans limitation de débit. L'incident montre ce qu'il faut éviter avec un agent auto-hébergé : exposition directe, identifiants faibles, absence de limitation et de surveillance.

Peut-on utiliser DeepSeek Harness depuis un téléphone ?

Oui, depuis un navigateur mobile. La version 0.2.2-rc.1 améliore la prise en charge des téléphones et des tablettes : clavier virtuel, navigation et mises en page étroites. Pour y accéder, publiez l'interface derrière Nginx en HTTPS avec authentification, ou connectez le téléphone au VPS par un VPN WireGuard pour garder dsh invisible depuis Internet.

Où DeepSeek Harness stocke-t-il les clés API ?

Dans le fichier .credentials.yaml du répertoire DSH_HOME, qui vaut ~/.dsh par défaut : /home/dsh/.dsh/.credentials.yaml dans ce guide. Les paramètres ne gardent qu'une référence vers la clé. Réservez ce répertoire à l'utilisateur dsh (chmod 700 sur son répertoire personnel), incluez-le dans vos sauvegardes chiffrées, et utilisez des clés dédiées au serveur, révocables sans toucher à vos autres usages.