La migración o respaldo de grandes directorios (en este caso, 36 GB) entre servidores remotos presenta desafíos de permisos, estabilidad de conexión y seguridad. A continuación, se detalla el procedimiento profesional para realizar una sincronización íntegra utilizando rsync sobre un puerto SSH no estándar y con elevación de privilegios.
1. Introducción al Escenario
El objetivo es copiar el contenido de un directorio protegido (/mnt/www_data/) desde un Servidor Origen (Remote) hacia un Servidor de Destino (Local), bajo las siguientes condiciones:
- Acceso SSH: Puerto personalizado (ej. 2222).
- Privilegios: El usuario requiere
sudopara leer los datos de origen. - Eficiencia: Sincronización incremental (solo copia lo que ha cambiado).
2. Preparación del Servidor Origen
Para que el proceso sea automatizado o fluido, el usuario remoto debe poder ejecutar el binario de rsync con privilegios de superusuario sin que la terminal se bloquee pidiendo una contraseña de sudo.
Configuración de Sudoers
- Acceda al servidor de origen vía SSH.
- Ejecute el comando:
sudo visudo. - Al final del archivo, añada la siguiente regla (reemplace
usuario_remotopor el suyo):usuario_remotoALL=(ALL) NOPASSWD: /usr/bin/mysqldump, /usr/bin/mysql, /usr/bin/mkdir, /usr/bin/chown, /usr/bin/rsync, /usr/bin/rm
Esta configuración permite quersyncy Mariadb lean archivos restringidos sin intervención humana durante la transferencia.
3. Ejecución del Comando de Sincronización
Desde el Servidor de Destino, utilizaremos rsync con una combinación de flags optimizada para grandes volúmenes de datos.
El comando maestro
rsync -avhP -e "ssh -p 2222" --rsync-path="sudo rsync" usuario_remoto@servidor_origen.pe:/mnt/www_data /ruta/local/backup/
Desglose de Parámetros:
-a(Archive): Preserva permisos, propietarios, grupos y fechas de modificación. Es recursivo.-v(Verbose): Muestra los detalles de los archivos que se están procesando.-h(Human-readable): Muestra los tamaños de archivo en formato legible (KB, MB, GB).-P(Progress + Partial): * Muestra una barra de progreso y velocidad en tiempo real.- Permite reanudar la transferencia si la conexión se corta, manteniendo los archivos parcialmente descargados.
-e "ssh -p 2222": Especifica el protocolo de transporte y el puerto personalizado.--rsync-path="sudo rsync": Instruye al servidor remoto a ejecutar rsync como root, permitiendo la lectura de archivos con permisos restringidos.
4. Consideraciones sobre el Slash (/) en las Rutas
En rsync, la barra diagonal final en la ruta de origen cambia el comportamiento drásticamente:
.../mnt/www_data(Sin barra): Copia la carpeta y su contenido. El resultado será/backup/www_data/....../mnt/www_data/(Con barra): Copia únicamente el contenido de la carpeta. El resultado será/backup/archivo1,/backup/archivo2, etc.
5. Gestión de Sesiones con Screen
Debido a que 36 GB pueden tardar varias horas, es crítico evitar que la transferencia se detenga si cerramos nuestra terminal local o si el equipo entra en suspensión.
- Instale screen:
sudo apt install screen. - Inicie una sesión:
screen -S backup_proceso. - Ejecute el comando
rsync. - Para desconectarse sin detener el proceso: Presione
Ctrl + Ay luegoD. - Para retomar el monitoreo: Escribe
screen -r backup_proceso.
6. Verificación de Integridad
Una vez finalizada la transferencia, es vital confirmar que el tamaño de los datos en ambos extremos coincida.
En el Origen y Destino ejecute:
Bash
du -sh /ruta/del/directorio
Para una verificación más exhaustiva (Checksum): Si sospecha de archivos corruptos, añada el flag -c a su comando rsync. Esto comparará los archivos mediante hashes MD5 en lugar de solo tamaño y fecha, aunque consume más recursos de CPU.
7. Seguridad Post-Transferencia
Una vez completada la migración, se recomienda revertir los cambios en el archivo sudoers del servidor origen para mantener el principio de menor privilegio:
- Ejecute
sudo visudo. - Comente la línea agregada:Bash
# usuario_remoto ALL=(ALL) NOPASSWD: /usr/bin/rsync
8. Automatización mediante Cron Jobs (Respaldo Incremental)
Una de las mayores ventajas de rsync es su capacidad para realizar respaldos incrementales. Esto significa que, después de la primera copia de 36 GB, las siguientes ejecuciones solo transferirán los archivos nuevos o modificados, reduciendo el tiempo de horas a pocos minutos.
Paso 1: Configuración de Llaves SSH (Sin Contraseña)
Para que un script automatice la tarea, no puede detenerse a pedir una contraseña. Debemos establecer una relación de confianza entre los servidores.
- Generar llave en el servidor de destino:
ssh-keygen -t rsa -b 4096(Presione Enter a todo). - Enviar la llave al servidor de origen:
ssh-copy-id -p 2222 usuario_remoto@servidor_origen.pe
o
ssh-copy-id -p 2222 usuario_remoto@192.168.1.2
Qué pasará después:
Te pedirá la contraseña deusuario_remoto. o preguntará con. «Are you sure you want to continue connecting (yes/no/[fingerprint])?» responder: Yes - Verás un mensaje confirmando:
Number of key(s) added: 1. - ¡Listo! A partir de ese segundo, el «túnel» entre tu servidor destino y el servidor origen estará abierto y será permanente.
- Prueba: Intente conectar por SSH. Si entra sin pedir clave, la automatización es posible.
Paso 2: Creación del Script de Respaldo
Antes de crear el archivo .sh, debemos preparar la estructura de carpetas y los registros (logs) en tu máquina local.
1. Definir la Estructura de Directorios
Es una buena práctica separar el script de los datos y de los reportes de error. Ejecuta estos comandos en tu Debian 11:
Bash
# Crear carpeta para los scripts
mkdir -p ~/scripts
# Crear carpeta para los registros (logs)
mkdir -p ~/backup/logs
# Crear la carpeta donde se mantendrá la copia sincronizada
mkdir -p ~/backup/sincronizacion_continua
2. Verificar la Ruta del Binario de Rsync
El script necesita saber exactamente dónde está rsync para evitar errores de «comando no encontrado». Confirma la ruta con:
Bash
which rsync
(Normalmente responderá /usr/bin/rsync).
Cree un archivo llamado backup_diario.sh en su servidor de destino con el siguiente contenido:
#!/bin/bash
# =================================================================
# SCRIPT DE RESPALDO DIARIO
# Descripción: Genera volcados SQL individuales y sincroniza archivos
# =================================================================
# 1. CONFIGURACIÓN
FECHA=$(date +%Y-%m-%d_%H-%M)
LOG_FILE="/home/usuariodestino/backup/logs/backup_$FECHA.log"
ORIGEN_IP="192.168.1.2"
USUARIO_REMOTO="usuario_remoto"
PUERTO_SSH="2222"
DIR_ORIGEN="/mnt/www_data"
DIR_DESTINO="/home/usuariodestino/backup/sincronizacion_continua"
DIR_SQL_REMOTO="/mnt/www_data/backups_sql"
# Crear carpetas locales si no existen
mkdir -p /home/usuariodestino/backup/logs
mkdir -p $DIR_DESTINO
echo "==========================================================" >> $LOG_FILE
echo "INICIO DEL PROCESO: $(date)" >> $LOG_FILE
echo "==========================================================" >> $LOG_FILE
# 2. GENERACIÓN DE SQL EN EL SERVIDOR REMOTO (DERECHO)
echo "[1/3] Generando volcados SQL en origen..." >> $LOG_FILE
ssh -p $PUERTO_SSH $USUARIO_REMOTO@$ORIGEN_IP << 'EOF' >> $LOG_FILE 2>&1
# Preparar directorio de volcado
sudo mkdir -p /mnt/www_data/backups_sql
sudo chown usuario_remoto:usuario_remoto /mnt/www_data/backups_sql
# Rutas absolutas
MYSQL="/usr/bin/mysql"
DUMP="/usr/bin/mysqldump"
# Obtener lista de bases de datos con sudo
DBS=$(sudo $MYSQL -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|mysql|sys)")
for DB in $DBS; do
echo "Exportando base de datos: $DB"
sudo $DUMP --single-transaction --quick --lock-tables=false "$DB" > "/mnt/www_data/backups_sql/${DB}.sql"
done
echo "Volcados SQL completados con éxito."
EOF
# 3. SINCRONIZACIÓN DE ARCHIVOS Y SQL (RSYNC)
echo "[2/3] Iniciando sincronización Rsync (36GB aprox)..." >> $LOG_FILE
# -a: archivo, -v: verboso, -h: legible, --delete: para espejar exactamente el origen
rsync -avh --delete -e "ssh -p $PUERTO_SSH" --rsync-path="sudo rsync" \
$USUARIO_REMOTO@$ORIGEN_IP:$DIR_ORIGEN/ $DIR_DESTINO/ >> $LOG_FILE 2>&1
# 4. VALIDACIÓN DE RESULTADO Y LIMPIEZA
if [ $? -eq 0 ]; then
echo "[3/3] Sincronización exitosa. Limpiando archivos temporales en origen..." >> $LOG_FILE
ssh -p $PUERTO_SSH $USUARIO_REMOTO@$ORIGEN_IP "sudo rm -f $DIR_SQL_REMOTO/*.sql" >> $LOG_FILE 2>&1
echo "==========================================================" >> $LOG_FILE
echo "RESULTADO: RESPALDO COMPLETADO Y LIMPIO" >> $LOG_FILE
else
echo "==========================================================" >> $LOG_FILE
echo "RESULTADO: ERROR EN LA TRANSFERENCIA. REVISAR LOG." >> $LOG_FILE
fi
echo "FIN DEL PROCESO: $(date)" >> $LOG_FILE
echo "==========================================================" >> $LOG_FILE
Script opcional para notificación vía email desde el servidor de origen, para ello debe tener instalado «msmtp» el servidor de origen.
#!/bin/bash
# =================================================================
# SCRIPT DE RESPALDO COMPLETO + NOTIFICACION CON EMAIL
# Emisor/Receptor: usuario.remoto@servidororigen.pe
# =================================================================
# 1. CONFIGURACIÓN
FECHA=$(date +%Y-%m-%d_%H-%M)
LOG_FILE="/home/usuariodestino/backup/logs/backup_$FECHA.log"
ORIGEN_IP="192.168.1.2"
USUARIO_REMOTO="usuario_remoto"
PUERTO_SSH="2222"
DIR_ORIGEN="/mnt/www_data"
DIR_DESTINO="/home/usuariodestino/backup/sincronizacion_continua"
DIR_SQL_REMOTO="/mnt/www_data/backups_sql"
EMAIL_CUENTA="usuario.remoto@servidororigen.pe"
mkdir -p /home/usuariodestino/backup/logs
echo "==========================================================" >> $LOG_FILE
echo "INICIO DEL PROCESO: $(date)" >> $LOG_FILE
echo "==========================================================" >> $LOG_FILE
# 2. GENERACIÓN DE SQL EN ORIGEN
echo "[1/3] Generando volcados SQL en origen..." >> $LOG_FILE
ssh -p $PUERTO_SSH $USUARIO_REMOTO@$ORIGEN_IP << 'EOF' >> $LOG_FILE 2>&1
sudo mkdir -p /mnt/www_data/backups_sql
sudo chown usuario_remoto:usuario_remoto /mnt/www_data/backups_sql
DBS=$(sudo /usr/bin/mysql -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|mysql|sys)")
for DB in $DBS; do
echo "Respaldando: $DB"
sudo /usr/bin/mysqldump --single-transaction --quick --lock-tables=false "$DB" > "/mnt/www_data/backups_sql/${DB}.sql"
done
EOF
# 3. SINCRONIZACIÓN RSYNC
echo "[2/3] Sincronizando archivos hacia Debian 11..." >> $LOG_FILE
rsync -avh --delete -e "ssh -p $PUERTO_SSH" --rsync-path="sudo rsync" \
$USUARIO_REMOTO@$ORIGEN_IP:$DIR_ORIGEN/ $DIR_DESTINO/ >> $LOG_FILE 2>&1
# 4. VALIDACIÓN Y LIMPIEZA
if [ $? -eq 0 ]; then
echo "[3/3] Sincronización exitosa. Limpiando origen..." >> $LOG_FILE
ssh -p $PUERTO_SSH $USUARIO_REMOTO@$ORIGEN_IP "sudo rm -f $DIR_SQL_REMOTO/*.sql" >> $LOG_FILE 2>&1
ESTADO_FINAL="EXITOSO"
else
echo "[!] ERROR EN RSYNC. No se limpió el origen." >> $LOG_FILE
ESTADO_FINAL="FALLIDO"
fi
echo "FIN: $(date)" >> $LOG_FILE
echo "==========================================================" >> $LOG_FILE
# 5. ENVÍO DE CORREO (AUTO-ENVÍO)
# Forzamos el remitente con el flag -from de msmtp para asegurar la entrega
(
echo "Subject: Reporte Backup FCJP ($ESTADO_FINAL) - $FECHA"
echo "From: $EMAIL_CUENTA"
echo "To: $EMAIL_CUENTA"
echo ""
tail -n 35 "$LOG_FILE"
) | ssh -p $PUERTO_SSH $USUARIO_REMOTO@$ORIGEN_IP "msmtp --from=$EMAIL_CUENTA $EMAIL_CUENTA"
Notas
El flag
--deletees opcional. Si lo activa, los archivos que borre en el servidor de origen también se borrarán en el destino, manteniendo un espejo exacto.Explicación:
- Validación de Red (
ping): Antes de intentar copiar nada, el script verifica si el servidor origen responde por la IP privada. Si el cable se desconectó, el script se detiene y te avisa en el log.- Opción
--delete: Es vital para un respaldo incremental tipo «espejo». Si borras una imagen basura en el servidor origen, el script también la borrará en tu Debian 11 para no acumular basura y ahorrar espacio.- Manejo de Logs: Cada vez que el script corra, creará un archivo con la fecha (ej.
backup_2026-02-24_02-00.log). Esto te permite auditar qué archivos se bajaron y si hubo errores.- BatchMode=yes: Fuerza a SSH a fallar de inmediato si por alguna razón vuelve a pedir contraseña, evitando que el script se quede «colgado» infinitamente esperando una entrada manual.
Seguridad Anti-Fallos: Explica que el condicionalif [ $? -eq 0 ]actúa como un seguro de vida. Si el cable de red se desconecta o el disco se llena en medio del proceso, los archivos SQL se quedan en el servidor origen para que no pierdas nada.- Higiene del Servidor: Al usar
rm -f $DIR_SQL_REMOTO/*.sqlal final, el servidor de producción (origen) se mantiene siempre con espacio libre, evitando que los respaldos afecten el funcionamiento de la web.- Persistencia en el Destino: Aunque se borren en el origen, en tu Debian 11 (destino) los archivos seguirán existiendo dentro de la carpeta
sincronizacion_continua/backups_sql/hasta que el próximo respaldo exitoso los actualice.
Para que el sistema lo reconozca como un programa ejecutable, debes darle el permiso x. Ejecuta este comando:
chmod +x ~/scripts/backup_diario.sh
Pruebas
Es totalmente comprensible, esperar a que se sincronicen 36 GB solo para ver si el script funciona es poco práctico. Para probar la «lógica» del script (que conecte bien, que escriba el log y que encuentre las rutas) sin transferir los datos, tienes dos caminos rápidos:
Opción 1: El «Simulador» (--dry-run)
Esta es la mejor opción. Le dice a rsync que haga todo excepto copiar los archivos. Te mostrará qué archivos copiaría pero sin mover un solo byte real.
- Abre tu script:
nano ~/scripts/backup_diario.sh - Busca la línea de
rsyncy añade--dry-run:Bashrsync -avh --delete --dry-run \ -e "ssh -p $PUERTO_SSH -o BatchMode=yes" \ ... - Guarda (
Ctrl+O) y sal (Ctrl+X). - Ejecútalo:
bash ~/scripts/backup_diario.sh. - Revisa el log:
cat ~/backup/logs/backup_*.log. Verás que termina en segundos y dice «(DRY RUN)».
Opción 2: Probar con un solo archivo pequeño
Si quieres ver un archivo real siendo transferido para estar 100% seguro, puedes limitar el rsync para que solo vea un archivo específico (por ejemplo, el SQL que generamos).
Modifica temporalmente la variable DIR_ORIGEN en tu script:
Bash
# Cambia esto solo para la prueba:
DIR_ORIGEN="/mnt/www_data/backups_sql/db_full_backup.sql.gz"
Al ejecutar el script, solo buscará ese archivo, lo transferirá (o verá que ya existe) y terminará de inmediato.
¿Qué debes revisar en el Log tras la prueba?
- Verifica el resultado en la carpeta de destino:
ls -l /home/usuariodestino/backup/sincronizacion_continua/(Deberías ver el archivonombrearchivoprueba.phpallí, o la estructura de carpetas que lo contiene). - Verifica que el log se haya creado correctamente:Bash
ls -l ~/backup/logs/ cat ~/backup/logs/backup_$(date +%Y-%m-%d)*.log
Independientemente de la opción que elijas, verifica que el log contenga estas líneas:
- «Sincronizando datos…»: Indica que pasó la prueba del
ping. - «SENT… RECEIVED…»: Al final del log de rsync, esto confirma que hubo comunicación.
- «RESPALDO COMPLETADO EXITOSAMENTE»: Esto confirma que la lógica de salida (
$?) del script funciona.
Importante: Una vez que estés satisfecho con la prueba, recuerda quitar el --dry-run o restaurar la ruta DIR_ORIGENoriginal para que el respaldo real pueda suceder.
Paso 3: Programación en el Crontab
Para que el script se ejecute, por ejemplo, todos los días a las 01:00 horas, siga estos pasos:
- De permisos de ejecución al script:
chmod +x backup_diario.sh - Abra el editor de cron:
crontab -e
si es la primera vez, aparcera algo parecido a esto, presiona 1 para usar nano:
usuariodestino@debian11:~/backup/scripts$ crontab -e
no crontab for usuariodestino - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/nano <---- easiest
2. /usr/bin/vim.tiny
Choose 1-2 [1]:
1. Agregar la tarea
Baja hasta el final del archivo con las flechas del teclado y pega esta línea:
00 01 * * * /home/usuariodestino/backup/scripts/backup_diario.sh
2. Guardar y Salir
- Presiona
Ctrl + O(para escribir los cambios). - Presiona
Enter(para confirmar el nombre del archivo). - Presiona
Ctrl + X(para salir del editor).
3. Confirmar que se guardó
Si todo salió bien, la terminal te mostrará el mensaje: crontab: installing new crontab
Puedes verificarlo listando las tareas activas:
crontab -l