Table des matières :
- Cartographier une erreur SFTP : à quel étage ça casse ?
- Connexion : DNS, port, firewall, NAT, bannissement automatique
- Négociation SSH : empreinte, algorithmes, compatibilité OpenSSH
- Authentification : mot de passe vs clés, droits sur .ssh et erreurs piégeuses
- Sous-système SFTP : internal-sftp, chroot, “Subsystem request failed”
- Permissions serveur : POSIX, ACL, umask, SELinux/AppArmor (et cas PrestaShop)
- Méthode de diagnostic reproductible : logs, traces, et playbook en 10 minutes
Cartographier une erreur SFTP : à quel étage ça casse ?
Une erreur SFTP n’est jamais « une seule erreur ». Vous empilez au minimum : TCP (connectivité), SSH (négociation + authentification), SFTP (sous-système côté serveur), puis système de fichiers (droits, ACL, SELinux/AppArmor). Diagnostiquer efficacement consiste à identifier la couche impactée avant de toucher à sshd_config ou aux permissions du webroot.
Point de vocabulaire qui évite des malentendus (notamment entre équipes infra/dev et prestataires) :
- SFTP ≠ FTPS : SFTP passe dans SSH, tandis que FTPS est FTP + TLS (autre port, autre serveur, autre logique).
- SFTP n’est pas un service séparé dans la majorité des cas : c’est un subsystem lancé par
sshd. Donc “SFTP en panne” est souvent “SSH en panne” ou “sshd mal configuré”.
Définition utile (à rappeler aux équipes qui mélangent tout) : le SFTP est le SSH File Transfer Protocol, il passe dans le tunnel SSH. Le manuel OpenSSH le formule sans ambiguïté : “sftp is a file transfer program, similar to ftp, which performs all operations over an encrypted ssh transport.” (man page sftp(1), OpenSSH). Conséquence directe : si ssh ne marche pas, SFTP ne marchera pas non plus.
Pour aller vite, classez le symptôme avec ce mapping (les libellés varient selon FileZilla/WinSCP/CLI) :
| Message côté client | Couche probable | Première action utile |
|---|---|---|
Connection timed out / No route to host |
Réseau / firewall | nc -vz host 22, vérifier SG/NACL, fail2ban |
Connection refused |
Service SSH down / port | ss -lntp | grep :22, systemctl status ssh |
Host key verification failed |
SSH (known_hosts) | valider l’empreinte, gérer known_hosts |
No matching host key type found / no matching key exchange method |
SSH (algos) | mettre à jour client, ajuster algos côté serveur |
Permission denied (publickey,password) |
Auth | ssh -vvv, logs auth.log |
Subsystem request failed on channel 0 |
SFTP subsystem | Subsystem sftp ..., internal-sftp |
Permission denied lors d’un put/get |
FS/ACL/SELinux | namei -l, getfacl, context SELinux |
Astuce “gain de temps” : si vous ne savez pas où vous en êtes, testez d’abord ssh, puis sftp. Un ssh utilisateur@host qui échoue vous évite de chercher côté permissions de répertoire alors que le problème est réseau, clé hôte, ou algorithmes.
Si vous êtes en train de déployer un thème/module PrestaShop et que vous confondez un 403 HTTP avec un Permission denied SFTP, ne mélangez pas les incidents : le 403 est côté serveur web. Pour le diagnostic 403, voir l’article dédié : Erreur 403 Forbidden : causes et dépannage étape par étape.
Connexion : DNS, port, firewall, NAT, bannissement automatique
Commencez par confirmer que vous parlez au bon hôte et au bon port. Sur votre poste :
getent hosts sftp.exemple.tld
nc -vz sftp.exemple.tld 22
# ou si port non standard
nc -vz sftp.exemple.tld 2222
nc (netcat) vous dit en 1 seconde si le port répond. Si ça time-out : firewall réseau, security group cloud, ACL OVH, IP non autorisée, ou bannissement. Si c’est refused : service SSH arrêté, ou écoute sur un autre port. Côté serveur, vérifiez :
ss -lntp | grep -E ':(22|2222)\b'
systemctl status ssh # Debian/Ubuntu
journalctl -u ssh -S -10min
Compléments utiles quand le diagnostic “réseau” est ambigu :
- DNS : un mauvais enregistrement (ou une migration) peut pointer vers une ancienne IP.
dig +short sftp.exemple.tld(si disponible) ouresolvectl query sftp.exemple.tld(systemd).- Vérifiez aussi IPv6 : un client peut tenter AAAA en priorité ; si l’IPv6 est mal filtré, ça ressemble à un time-out “mystère”.
- Chemin réseau : un
traceroute -T -p 22 host(oumtr -T -P 22 host) peut révéler un filtrage en amont. - Windows (si vos équipes opèrent depuis un poste Windows) :
Test-NetConnection sftp.exemple.tld -Port 22donne rapidement l’état de la connectivité TCP.
Un point qui fait perdre des heures : fail2ban (ou un WAF/IDS du fournisseur) peut bannir votre IP après quelques essais. Dans ce cas la connexion peut alterner entre time-out et reset. Cherchez des lignes type Ban / Unban dans /var/log/fail2ban.log ou via fail2ban-client status sshd. C’est un “faux problème SFTP” : vous devez traiter la cause (mauvais login, rotation de clé) et/ou mettre l’IP en liste blanche (temporairement).
Mini-scénario (fréquent en agence / équipe distribuée) : vous administrez une boutique hébergée chez OVHcloud, Scaleway ou en région Paris (eu-west-3) ; vous testez depuis un coworking ou une box grand public. Le port 22 peut être bloqué en sortie par une politique réseau (entreprise, proxy) ou par un filtrage local. Dans ce cas, un bastion sur un port autorisé (ou un VPN d’entreprise) est souvent plus réaliste que “ouvrir partout”.
Enfin, sur des architectures modernes (reverse-proxy, bastion, Kubernetes), le « serveur SFTP » n’est parfois qu’un jump host. Si vous êtes en migration ou en GitOps, documentez clairement le chemin réseau (bastion -> nœud) et évitez les accès directs depuis des IP “de bureau”. Le check-list infra et les pièges d’archi sont très proches de ceux décrits dans Migration PrestaShop vers Kubernetes : checklist GitOps et pièges courants (même si ici on parle SSH/SFTP plutôt qu’Ingress).
Négociation SSH : empreinte, algorithmes, compatibilité OpenSSH
Quand le port répond mais que SFTP échoue, passez en mode verbeux. Côté client (Linux/macOS) :
ssh -vvv [email protected] -p 22
sftp -vvv -P 22 [email protected]
Le -vvv vous montre exactement où ça casse : échange de clés (KEX), choix du cipher, validation de l’hôte, etc. Si vous tombez sur Host key verification failed, ce n’est pas “un bug”. C’est known_hosts qui protège contre l’homme-du-milieu. En CI/CD, on gère ça proprement (pinning d’empreinte), pas en désactivant la vérification.
Deux commandes pratiques pour “objectiver” une empreinte (utile en runbook, et quand un prestataire vous envoie une empreinte à la main) :
ssh-keyscan -p 22 sftp.exemple.tld | ssh-keygen -lf -
# ou vérifier une clé hôte fournie (fichier):
ssh-keygen -lf /chemin/vers/ssh_host_ed25519_key.pub
Les erreurs du type no matching key exchange method ou no matching host key type found sont fréquentes quand :
- le serveur a durci sa config (désactivation de RSA SHA-1, DSA, vieux KEX)
- votre client est trop vieux (VM Windows, appliance, outil legacy)
SSH évolue et c’est normal. Le cadre général est celui des RFC : “The Secure Shell (SSH) Protocol provides secure remote login and other secure network services over an insecure network.” (RFC 4251, IETF, https://www.rfc-editor.org/rfc/rfc4251). Quand serveur et client n’ont plus d’intersection d’algorithmes, la connexion s’arrête avant toute authentification.
Côté serveur OpenSSH, vérifiez la version et la politique d’algos :
sshd -T | egrep -i 'kexalgorithms|ciphers|macs|hostkeyalgorithms'
ssh -Q kex
ssh -Q key
Précaution : si vous “réactivez” des algorithmes obsolètes pour dépanner un client legacy, faites-le de manière temporaire et ciblée (par IP ou par utilisateur, via un Match Address / Match User), et documentez un plan de sortie (mise à jour client, remplacement outil). En environnement e-commerce exposé, la bonne trajectoire est généralement : mettre à jour le client (WinSCP, FileZilla, libssh2) ou passer par un bastion compatible.
Pour la doc officielle OpenSSH (référence pratique quand on doute d’une option), la page sshd_config d’OpenBSD est très fiable : https://man.openbsd.org/sshd_config
Authentification : mot de passe vs clés, droits sur .ssh et erreurs piégeuses
L’erreur la plus répandue reste Permission denied (publickey,password). Avant de réinitialiser le mot de passe « au hasard », lisez les logs serveur. Selon distro :
# Debian/Ubuntu
sudo tail -n 200 /var/log/auth.log
# RHEL/Alma/Rocky
sudo tail -n 200 /var/log/secure
# systemd
sudo journalctl -u ssh -S -30min
Cherchez des motifs clairs : Failed password, Invalid user, Too many authentication failures, User ... not allowed because listed in DenyUsers, ou encore l’incontournable : Authentication refused: bad ownership or modes for directory .... Cette dernière indique que les permissions POSIX du home (ou de ~/.ssh) sont trop permissives. Typiquement :
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~
chown -R user:user ~/.ssh
Pensez aussi aux causes “non SSH” qui finissent en échec SSH :
- Compte verrouillé / mot de passe expiré (courant après une politique de rotation) :
passwd -S useretchage -l user(selon distributions). - Shell interdit / compte sans shell : si vous forcez du SFTP-only, c’est OK, mais si vous attendez un shell et qu’il est désactivé (
/usr/sbin/nologin), certains outils peuvent se comporter différemment. - Méthodes d’auth : un serveur peut accepter
publickeymais refuserpassword(PasswordAuthentication no), ou exiger du MFA /keyboard-interactivevia PAM. Le client affichera parfois un message générique ; les logs serveur tranchent.
Si vous utilisez des clés, validez la chaîne complète : clé privée chargée dans l’agent (ssh-add -l), clé publique présente dans authorized_keys, et le bon utilisateur ciblé (une erreur classique est de pousser la clé sur root puis de tester avec deploy). En CI/CD, vous devez aussi gérer known_hosts et éviter les prompts interactifs. Sur ce point, le pattern “déploiement par job” est très proche de ce qui est détaillé dans PrestaShop CI/CD : générer des démos à la demande en minutes : le SFTP devient une dépendance à stabiliser (clés, secrets, rotation, logs).
Dernier piège : Too many authentication failures peut apparaître même avec la bonne clé si votre agent présente trop de clés et que le serveur coupe après MaxAuthTries. Forcer la clé côté client règle le problème :
ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes user@host
Sous-système SFTP : internal-sftp, chroot, “Subsystem request failed”
Si ssh fonctionne mais sftp échoue avec Subsystem request failed on channel 0, vous n’êtes plus dans l’auth : le serveur SSH ne lance pas (ou n’autorise pas) le sous-système SFTP. Dans OpenSSH, c’est déclaré dans sshd_config via Subsystem. Par défaut on voit souvent :
Subsystem sftp /usr/lib/openssh/sftp-server
# ou (recommandé)
Subsystem sftp internal-sftp
internal-sftp évite des dépendances de chemin et simplifie le chroot. Il permet aussi (utile en exploitation) d’ajouter des options de log et d’umask. Exemple fréquent :
Subsystem sftp internal-sftp -f AUTH -l INFO
Ce réglage remonte les événements SFTP dans syslog/journal (selon distro), ce qui aide à différencier un échec “auth” d’un échec “permissions” quand les clients ne remontent pas les détails.
La doc OpenSSH rappelle aussi une contrainte non négociable dès que vous chroot-ez un utilisateur : “At session startup sshd checks that all components of the pathname are root-owned directories which are not writable by group or others.” (man page sshd_config(5), OpenSSH). C’est exactement la source de beaucoup de “ça marchait hier” après un chown malheureux.
Checklist simple quand vous suspectez le chroot :
sshd -T | grep -i chrootpour voir la config effective (y compris lesMatch).- vérifier que chaque composant du chemin de
ChrootDirectoryestroot:rootet non group-writable/other-writable. - s’assurer qu’un dossier interne (ex.
upload/) est, lui, writable par l’utilisateur.
Exemple minimal de configuration SFTP-only (attention : à tester sans fermer votre session SSH active, et valider sshd -t avant reload) :
Match User sftpuser
ForceCommand internal-sftp
ChrootDirectory /var/sftp/%u
PasswordAuthentication yes
PermitTunnel no
AllowAgentForwarding no
X11Forwarding no
PermitTTY no
Puis, côté filesystem : le répertoire de chroot doit être root:root et non writable, et vous créez un sous-dossier writable pour l’utilisateur :
mkdir -p /var/sftp/sftpuser/upload
chown root:root /var/sftp/sftpuser
chmod 755 /var/sftp/sftpuser
chown sftpuser:sftpuser /var/sftp/sftpuser/upload
chmod 755 /var/sftp/sftpuser/upload
Si vous faites du SFTP pour échanger des flux (ERP, EDI), ce modèle est plus robuste qu’un accès shell complet. Pour le contexte “SFTP dans des échanges inter-systèmes”, voir Intégration ERP : standards EDI, EDIFACT, AS2, SFTP et PEPPOL.
Permissions serveur : POSIX, ACL, umask, SELinux/AppArmor (et cas PrestaShop)
Les erreurs Permission denied au moment d’un put/rename sont 90% du temps du POSIX pur : mauvais owner, groupe incorrect, bit d’écriture absent sur un répertoire parent. La commande la plus rentable est namei, parce qu’elle déroule toute la chaîne de dossiers :
namei -l /var/www/prestashop/img
ls -ld /var/www/prestashop /var/www/prestashop/img
Sur une boutique PrestaShop (8.1.x ou 9.x) sous PHP-FPM (PHP 8.2/8.3), vous avez souvent deux identités en jeu : l’utilisateur SFTP (deploy, sftpuser) et l’utilisateur d’exécution web (www-data, php-fpm). Si vous uploadez des fichiers via SFTP en deploy:deploy mais que PHP écrit en www-data:www-data, vous créez vite des conflits sur var/cache/, img/, modules/ ou themes/.
Repère concret (à adapter à votre stack et à vos pratiques de déploiement) : les dossiers qui posent le plus souvent problème lors d’une mise à jour / install de module sont :
var/(cache, logs)img/(générations d’images, uploads selon modules)modules/(installation / upgrade)themes/(si vous déployez un thème par SFTP)download/etupload/(selon configuration et modules)
Le correctif propre n’est pas chmod -R 777 (c’est une régression sécurité), mais une stratégie de groupe :
- un groupe commun (ex.
shop) chgrp -R shopsur les répertoires devant être modifiableschmod -R g+rwXet setgid sur les dossiers (bit2) pour conserver le groupe
groupadd shop
usermod -aG shop deploy
usermod -aG shop www-data
chgrp -R shop /var/www/prestashop/var /var/www/prestashop/img
chmod -R g+rwX /var/www/prestashop/var /var/www/prestashop/img
find /var/www/prestashop/var /var/www/prestashop/img -type d -exec chmod g+s {} \;
Deux détails “perms” qui expliquent des comportements incohérents :
- umask : selon le serveur SFTP (et sa config), les fichiers uploadés peuvent sortir en
0644ou0664. Avecinternal-sftp, vous pouvez contrôler l’umask côté serveur via-u(ex.-u 0002pour favoriser l’écriture groupe). À utiliser si votre modèle “groupe commun + setgid” est votre standard. - rename / atomicité : certains clients uploadent en fichier temporaire puis font un
rename. Si le répertoire autorise l’écriture mais pas la suppression/rename (droits sur le dossier), vous verrez des erreurs lors de la finalisation plutôt qu’au début de transfert.
Si malgré des perms correctes vous avez encore des refus, regardez les ACL et les contrôles Mandatory Access Control. ACL :
getfacl -p /var/www/prestashop/img | sed -n '1,120p'
SELinux (RHEL-like) : un contexte bloquant donne souvent un “permission denied” sans logique POSIX. Vérifiez getenforce et les logs (ausearch -m avc -ts recent). AppArmor (Ubuntu) : profils sshd ou php-fpm peuvent aussi limiter.
Enfin, n’écartez pas les “faux Permission denied” : un système de fichiers monté en lecture seule (incident stockage), un quota dépassé, ou un disque plein se traduisent souvent par des erreurs côté client qui ressemblent à des refus d’écriture. Vérifications rapides :
df -h
mount | grep -E ' /var| /var/www'
Ce sont des sujets de durcissement : si vous cherchez une méthode plus globale, l’article Symfony : sécuriser un serveur PHP avec hardening et gestion CVE donne des repères utiles (même si l’exécution n’est pas “Symfony-only”).
Méthode de diagnostic reproductible : logs, traces, et playbook en 10 minutes
Côté client, ne restez pas sur l’UI. Les logs FileZilla/WinSCP sont utiles, mais ssh -vvv et sftp -vvv sont la source de vérité pour comprendre la négociation et l’auth. Conservez ces traces dans votre ticket (sans secrets). Ajoutez systématiquement : IP source, hostname, port, user, type d’auth (password/key), et horodatage.
Côté serveur, standardisez un playbook minimal :
1) journalctl -u ssh -S -15min (ou auth.log) pour corréler la tentative
2) sshd -T | less pour voir la config effective (incluant Match)
3) ss -lntp pour confirmer l’écoute
4) namei -l + getfacl sur le chemin cible si c’est un problème d’écriture
En pratique, vous pouvez “industrialiser” ce playbook avec 3 recherches rapides dans les logs (sans forcément ajouter d’outils) :
- Auth échoue :
grep -E "Failed password|Invalid user|Authentication refused|Too many authentication failures" /var/log/auth.log - SFTP subsystem/chroot :
grep -E "subsystem request for sftp|internal-sftp|chroot" /var/log/auth.log - Bannissement :
grep -E "Ban|Found|Unban" /var/log/fail2ban.log
Ce playbook s’intègre bien à une démarche plus large de dépannage prod. Si vous avez déjà un référentiel d’incidents, vous pouvez l’adosser à Dépannage boutique en ligne : 30 pannes classées par symptôme pour éviter que “SFTP en panne” devienne le fourre-tout de tous les problèmes d’exploitation.
Enfin, évitez le diagnostic en aveugle : centralisez les logs SSH (auth + fail2ban) dans un moteur de recherche de logs si vous avez du volume et des accès distribués. Si vous êtes déjà équipé sur l’écosystème OVH, l’approche décrite dans OVHcloud Managed OpenSearch : moteur NoSQL managé pour logs et recherche s’applique directement : un dashboard “Failed password / Invalid user / Subsystem failed” réduit drastiquement le MTTR, et vous permet de distinguer incident réel vs bruit (scans bots sur le port 22).



