Transférer des fichiers (rsync)
rsync est l'outil de référence pour synchroniser des fichiers entre deux machines via SSH. C'est ce qu'on utilise pour:
- Migrer des données entre serveurs (anciens => nouveaux)
- Synchroniser des dossiers de manière incrémentale (ne re-transfère que les diffs)
- Faire des backups rapides
Pourquoi pas scp / curl / gokapi ?
scp ne reprend pas les transferts interrompus. curl et gokapi ont un overhead HTTP énorme (testé: 7 Mb/s pour 250 GB, intenable). rsync over SSH sature le lien réel et reprend automatiquement où il s'est arrêté.
Syntaxe de base
rsync [options] SOURCE DESTINATIONLe premier argument est la source, le deuxième la destination. La direction se détermine en fonction d'où se trouve user@host: dans la commande.
| Cas | Commande | Résultat |
|---|---|---|
| Pull (depuis remote vers local) | rsync user@remote:/path/ /local/ | Récupère depuis remote |
| Push (depuis local vers remote) | rsync /local/ user@remote:/path/ | Envoie vers remote |
| Local => local | rsync /a/ /b/ | Copie sur la même machine |
Le slash final est CRUCIAL
/path/source/(avec slash) => copie le contenu desource/dans la destination/path/source(sans slash) => copiesourcecomme un sous-dossier dans la destination
# Bon
rsync /data/images/ remote:/backup/images/ # => /backup/images/<fichiers>
# Crée un niveau de trop
rsync /data/images remote:/backup/images/ # => /backup/images/images/<fichiers>Options à toujours utiliser
| Option | Rôle |
|---|---|
-a | Mode archive: préserve perms, timestamps, symlinks, ownership |
-v | Verbose, montre les fichiers transférés |
--progress | Barre de progression par fichier |
--partial | Garde les fichiers partiellement transférés en cas d'interruption |
--inplace | Écrit directement dans le fichier final (pas de copie temp) |
Pourquoi --partial --inplace
Sans ces flags, un fichier interrompu est jeté à la poubelle, et la prochaine reprise recopie tout. Avec --inplace, rsync reprend au byte exact où il s'est arrêté. Indispensable pour les gros fichiers (vidéos, archives).
Pour les gros transferts (>10 GB)
rsync -av --progress --partial --inplace \
-e "ssh -T -o Compression=no" \
/source/ user@remote:/dest/| Option SSH | Rôle |
|---|---|
-T | Désactive l'allocation tty (overhead inutile) |
-o Compression=no | Ne compresse pas (les médias/zip sont déjà compressés, perte sèche CPU) |
Compression utile dans certains cas
Si tu transfères du texte (logs, dumps SQL, code source) sur un lien lent, garde la compression SSH activée - voire ajoute -z à rsync. Mais pour des médias (jpg, png, mp4, pdf), la compression ralentit sans rien apporter.
Cas 1 - Sans jumphost (le plus simple)
Tu as accès SSH direct entre les deux machines (port 22 ouvert dans le SG, clé autorisée).
Pull (depuis le serveur de destination)
rsync -av --progress --partial --inplace \
-e "ssh -T -o Compression=no" \
user@source-host:/data/source/ \
/data/dest/Push (depuis le serveur source)
rsync -av --progress --partial --inplace \
-e "ssh -T -o Compression=no" \
/data/source/ \
user@dest-host:/data/dest/Pull ou push ?
- Pull est généralement préféré: tu opères depuis le nouveau serveur où tu fais déjà ton setup.
- Push est obligatoire quand le serveur source a une whitelist d'IP en entrée (ne peut pas être atteint depuis le nouveau).
Cas 2 - Avec jumphost (ProxyJump)
Quand le serveur destination est dans un sous-réseau privé accessible uniquement via un bastion SSH.
Architecture typique chez Spektrum
[Source] ──ssh──> [Bastion NGINX] ──ssh──> [Apps-Prod / DB-Prod / etc.]
IP publique IP interneCommande directe avec -J
rsync -av --progress --partial --inplace \
-e "ssh -T -J user@bastion-host -o Compression=no" \
/data/source/ \
user@dest-host:/data/dest/Authentification sur les deux machines
Ta clé SSH doit être autorisée dans ~/.ssh/authorized_keys du bastion ET dans celui de la destination. Le bastion ne fait que router la connexion, il ne masque pas l'auth de la cible.
Cas 3 - Avec SSH config (recommandé pour usage régulier)
Plutôt que répéter -e "ssh -J ..." à chaque commande, déclare les hosts dans ~/.ssh/config:
Host bastion-prod
HostName 83.228.201.182
User migration
IdentityFile ~/.ssh/id_ed25519
Host apps-prod
HostName 89.47.48.11
User migration
IdentityFile ~/.ssh/id_ed25519
ProxyJump bastion-prod
Host db-prod
HostName 89.47.48.14
User migration
IdentityFile ~/.ssh/id_ed25519
ProxyJump bastion-prodPermissions du fichier
~/.ssh/config doit être en mode 600 et appartenir à ton user - sans sudo.
chmod 600 ~/.ssh/configSi tu fais sudo chmod, le fichier passe en owner root et SSH ne peut plus le lire. Pour réparer:
sudo chown <user>:<user> ~/.ssh/configAvec ça, rsync devient ultra simple:
# Push vers apps-prod via bastion-prod (jumphost configuré dans le config)
rsync -av --progress --partial --inplace \
-e "ssh -T -o Compression=no" \
/data/source/ \
apps-prod:/data/dest/Tu peux aussi tester l'accès en une commande:
ssh apps-prod 'echo OK && df -h /data'Cas 4 - Migration avec clé temporaire
Pour une migration ponctuelle où tu ne veux pas exposer ta clé personnelle, génère une clé dédiée:
1. Générer la clé sur la source
ssh-keygen -t ed25519 -f ~/.ssh/migration_tmp -N "" -C "migration-tmp-$(date +%Y%m%d)"
cat ~/.ssh/migration_tmp.pub2. Autoriser la pubkey sur les deux machines
Sur le bastion et sur la destination, ajouter la pubkey à ~/.ssh/authorized_keys du user qui fera le transfert (migration typiquement).
echo "<contenu de migration_tmp.pub>" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keysOu via ssh-copy-id chaîné:
ssh-copy-id -i ~/.ssh/migration_tmp.pub user@bastion
ssh-copy-id -i ~/.ssh/migration_tmp.pub -o "ProxyJump user@bastion" user@dest3. Tester avant le gros transfert
ssh migration-apps-prod 'echo OK && df -h /data && touch /data/dest/.test && rm /data/dest/.test && echo writable'4. Permissions destination
Le user de transfert doit pouvoir écrire dans le dossier cible. Depuis un user avec sudo sur la destination:
sudo mkdir -p /data/<projet>/images
sudo chown -R migration:spek /data/<projet>/imagesGroupe spek chez Spektrum
Le user migration n'a pas de groupe propre - utilise spek (groupe partagé) ou la syntaxe migration: (= groupe primaire). migration:migration échoue avec invalid group.
5. Cleanup après la migration
Sur la source:
rm ~/.ssh/migration_tmp ~/.ssh/migration_tmp.pub
# nettoyer les blocs Host migration-* dans ~/.ssh/configSur le bastion + destination:
sed -i '/migration-tmp-/d' ~/.ssh/authorized_keysSur la destination, repasser l'owner du dossier au user qui exploite l'app:
sudo chown -R clement:spek /data/<projet>/imagesRésister aux coupures de session - tmux
Une connexion SSH coupée ⇒ le rsync s'arrête. Pour des transferts de plusieurs heures, toujours lancer dans tmux:
# 1. Créer une session
tmux new -s migration
# 2. Lancer rsync dedans (commande normale)
rsync -av --progress --partial --inplace -e "ssh -T -o Compression=no" /source/ apps-prod:/dest/
# 3. Détacher: Ctrl+B puis D
# La session continue de tourner en background
# 4. Réattacher plus tard depuis n'importe quelle session SSH
tmux attach -t migrationTabby intercepte Ctrl+B
Tabby (et certains autres terminaux) capturent Ctrl+B pour leur propre usage. Si Ctrl+B + D ne marche pas, détache depuis une autre session SSH:
tmux detach-client -s migration # -s = session, pas -t qui cherche un clientOu rebind tmux dans ~/.tmux.conf:
unbind C-b
set -g prefix C-a
bind C-a send-prefixSuivi du transfert détaché
Trois façons de regarder l'avancement sans interrompre:
Snapshot du pane tmux
tmux capture-pane -t migration -p | tail -30En continu (rafraîchi toutes les 5s):
watch -n 5 'tmux capture-pane -t migration -p | tail -20'Comparaison des tailles
# Source
du -sh /data/source/
# Destination via SSH
ssh apps-prod 'du -sh /data/dest/'Le ratio te donne le pourcentage transféré.
Bande passante temps réel
sudo apt install -y iftop
sudo iftop -i eth0Filtre par IP de destination si besoin pour ne voir que ce trafic.
Vérification d'intégrité après transfert
# Compter les fichiers et tailles des deux côtés
find /data/source/ -type f | wc -l
du -sh /data/source/
ssh apps-prod 'find /data/dest/ -type f | wc -l && du -sh /data/dest/'Les compteurs et tailles doivent correspondre. Si pas exact, relance simplement le rsync - il est idempotent et ne re-transfère que ce qui manque ou diffère.
Vérification de checksums
Pour une vérification stricte (lente), ajoute --checksum au rsync:
rsync -avc --progress source/ dest/Ça compare les hash de chaque fichier au lieu de juste taille+mtime. À utiliser avec parcimonie sur de gros volumes.
Options avancées
Exclure des fichiers / dossiers
rsync -av --progress \
--exclude '*.tmp' \
--exclude 'cache/' \
--exclude '.git/' \
/source/ user@remote:/dest/Ou via un fichier d'exclusion:
echo -e "*.tmp\ncache/\n.git/" > /tmp/excludes.txt
rsync -av --exclude-from=/tmp/excludes.txt /source/ user@remote:/dest/Synchronisation en miroir (--delete)
rsync -av --delete /source/ user@remote:/dest/--delete supprime côté destination les fichiers qui n'existent plus côté source. Dangereux - ne pas combiner avec un mauvais slash final, tu pourrais effacer trop.
Toujours tester avec --dry-run
Avant un rsync avec --delete, fais un essai à blanc:
rsync -avn --delete /source/ user@remote:/dest/Le -n (--dry-run) montre ce qui serait fait sans rien modifier.
Limiter la bande passante
Pour ne pas saturer le lien (utile en heures ouvrées sur lien partagé):
rsync -av --bwlimit=10000 /source/ user@remote:/dest/--bwlimit=10000 limite à ~10 MB/s.
Parallélisation pour saturer un gros lien
rsync est mono-thread. Pour saturer un lien 1 Gbps+, parallelise par sous-dossier:
ssh source-host 'ls /data/source/' | \
parallel -j 4 rsync -av --partial --inplace \
-e "ssh -T -o Compression=no" \
source-host:/data/source/{} /data/dest/{}-j 4 = 4 transferts simultanés.

