Cuando necesitas mover archivos entre máquinas, tienes tres herramientas que trabajan sobre SSH: scp, rsync y sftp. Las tres usan el mismo canal cifrado, pero sirven para casos distintos y tienen mecánicas internas muy diferentes.
scp (Secure Copy) es la más simple: abre una conexión SSH, copia, cierra. Históricamente usaba el protocolo SCP, que delega la expansión de globs (patrones como *.log) al lado remoto de forma inconsistente. Desde OpenSSH 9.0 el cliente scp usa internamente SFTP por defecto para resolver esos problemas, pero la interfaz sigue siendo la misma y sigue sin poder reanudar una transferencia interrumpida. Úsalo cuando quieres copiar un archivo o dos de forma puntual y no te importa empezar de cero si se corta.
rsync es una herramienta de sincronización, no de copia. Su algoritmo calcula una suma de verificación por bloques y solo transfiere los fragmentos que han cambiado entre origen y destino. Eso lo hace ideal para backups incrementales, despliegues y cualquier situación donde muevas datos repetidamente sobre el mismo par de directorios. Trabaja sobre SSH por defecto cuando especificas un destino remoto con la sintaxis usuario@host:/ruta. Si te equivocas con el slash final, el resultado es un directorio completamente distinto al que esperabas —lo veremos en detalle.
sftp abre una sesión interactiva similar a FTP clásico, pero cifrada. Útil cuando necesitas explorar el sistema de archivos remoto antes de decidir qué copiar, o cuando trabajas con usuarios que necesitan una interfaz familiar sin acceso a shell completo.
El riesgo real está en rsync: --delete borra en destino lo que no existe en origen. Sin un --dry-run previo, puedes vaciar un directorio de producción en segundos.
# Escenario: sincronizar un directorio de proyecto local con un servidor,
# preservar permisos, mostrar progreso, comprimir en tránsito,
# y eliminar en remoto los archivos que ya borramos en local.
# 1. Primero, SIEMPRE simula con --dry-run para ver qué tocará rsync
rsync -avz --delete --dry-run \
~/proyectos/webapp/ \
deploy@192.168.1.50:/srv/webapp/
# 2. Si la salida tiene sentido, ejecuta sin --dry-run
rsync -avzP --delete \
~/proyectos/webapp/ \
deploy@192.168.1.50:/srv/webapp/
# 3. Para copiar un único archivo cuando no necesitas sincronización
scp ~/proyectos/webapp/config/nginx.conf \
deploy@192.168.1.50:/etc/nginx/sites-available/webapp.conf
# 4. Para explorar el servidor antes de copiar nada
sftp deploy@192.168.1.50
# Una vez dentro del prompt sftp>:
# ls -la /srv/webapp/
# get /srv/webapp/logs/error.log <- descarga al directorio local actual
# put ~/local/fix.patch /tmp/ <- sube un archivo
# exit
Lo que está pasando en cada línea
El slash en ~/proyectos/webapp/ es la decisión más crítica de todo el bloque. Con el slash al final, rsync interpreta el argumento como “el contenido de este directorio”. Sin él, interpreta el directorio mismo. En el ejemplo, webapp/ como origen y /srv/webapp/ como destino significa que los archivos de webapp/ llegan directamente dentro de /srv/webapp/. Si hubieras escrito webapp sin slash, rsync habría creado /srv/webapp/webapp/ —un directorio anidado que no esperabas.
Las opciones -avzP son una combinación habitual en producción:
– -a es archive, un atajo para -rlptgoD: recursivo, preserva symlinks, permisos, timestamps, propietario y grupo, y dispositivos especiales. Sin -a pierdes metadatos.
– -v activa el verbose para ver qué archivos se tocan.
– -z comprime los datos en tránsito. Ayuda en enlaces lentos o con texto plano; con archivos ya comprimidos (.tar.gz, imágenes) añade CPU sin beneficio real.
– -P combina --progress (barra de progreso por archivo) y --partial (guarda los fragmentos ya transferidos si la conexión se corta, para reanudar después). Esto es lo que scp no puede hacer.
--delete elimina en /srv/webapp/ cualquier archivo que no esté en ~/proyectos/webapp/. Es exactamente lo que quieres para un despliegue limpio, y exactamente lo que no quieres si el destino tiene archivos generados en producción (logs, uploads de usuarios) que no viven en tu origen. En ese caso excluyes esas rutas con --exclude='logs/'.
El --dry-run del paso 1 no es opcional cuando usas --delete. La salida te muestra línea a línea qué se crearía, actualizaría o eliminaría. Cuesta diez segundos leerla; recuperarse de un borrado accidental puede costar horas.
scp en el paso 3 tiene sentido aquí porque estás copiando un solo archivo de configuración a una ruta específica con nombre distinto. rsync para un archivo puntual es matar moscas a cañonazos, aunque funciona perfectamente.
sftp en el paso 4 es útil cuando el servidor tiene ForceCommand internal-sftp en su configuración SSH, un patrón común para usuarios de transferencia que no deben tener shell. En ese contexto, scp y rsync fallan porque intentan ejecutar comandos en remoto; sftp usa el subsistema SFTP directamente y funciona sin restricciones adicionales.
N° 85