¿Cómo sincronizar archivos entre dos controles remotos?


54

Me gustaría transferir archivos entre dos hosts remotos utilizando un shell local, pero parece que rsync no admite la sincronización si se especifican dos controles remotos de la siguiente manera:

$ rsync -vuar host1:/var/www host2:/var/www
The source and destination cannot both be remote.

¿Qué otras soluciones / comandos podría usar para lograr resultados similares?



1
En realidad, puede sincronizar entre 2 hosts remotos aprovechando sshfs en un tercer host. Simplemente use sshfs para montar host1 y host2 en el host 3. Luego rsync entre 1 y 2.
William Legg

@WilliamLegg la desventaja de usar sshfses que luego rsyncve los sistemas de archivos de origen y de destino como locales, por lo que deshabilita su algoritmo delta. En ese punto, casi podrías usarlo cp -p. Vea la respuesta que propone esto y sus comentarios posteriores.
roaima

Respuestas:


50

Como ha descubierto, no puede usar rsync con una fuente remota y un destino remoto. Suponiendo que los dos servidores no pueden comunicarse directamente entre sí, es posible usar ssh para hacer un túnel a través de su máquina local.

En lugar de

rsync -vuar host1:/var/www host2:/var/www

puedes usar esto

ssh -R localhost:50000:host2:22 host1 'rsync -e "ssh -p 50000" -vuar /var/www localhost:/var/www'

En caso de que se lo pregunte, la -Ropción configura un canal inverso desde el puerto 50000 en el host1 que se asigna (a través de su máquina local) al puerto 22 en el host2. No hay conexión directa de host1 a host2.


1
Me gusta la solución de @ roaima, pero no pude hacer que funcione para mí debido a varias razones. Al final solía sshfsmontar ambos directorios remotos localmente, luego los utilicé rsyncen los dos directorios montados localmente.
aidan

¿Es posible ver un ejemplo donde se usa una clave? Tiene problemas para descubrir cómo usar -ipara especificar las claves necesarias para los comandos ssh.
onassar

@onassar agrega el -i key...parámetro dentro de las comillas después del sshcomando. Si eso no le ayuda, no dude en hacer una Nueva Pregunta, haciendo referencia a esta respuesta para el contexto
roaima

1
la conexión inversa no lee la configuración ~ / .ssh / en el lado local - necesita usar algo que pueda resolverse como si no hubiera un archivo de configuración SSH
Florenz Kley

1
'Suponiendo que los dos servidores no pueden hablar directamente entre sí'. Esta solución funciona alrededor de un firewall o un problema de NAT que impide una conexión SSH directa . Sin embargo, no aborda el caso en el que, por razones de seguridad, el usuario de origen (en host1) no tiene clave o credenciales o permisos de escritura insuficientes en el destino. Para eso vea la solución de Kevin Cox, o recurra a una conexión indirecta usando un script o scp -3.
Cedric Knight

22

No dijiste por qué no querías iniciar sesión en un host y luego copiar al otro, así que compartiré una de mis razones y soluciones.

No pude iniciar sesión en una máquina y luego sincronizar con la otra porque ninguno de los hosts tenía una clave SSH que podía iniciar sesión en la otra. Resolví esto usando el reenvío de agente SSH para permitir que el primer host use mi clave SSH mientras estaba conectado.

ADVERTENCIA: el reenvío SSH permite que el host use su clave SSH durante la duración de su inicio de sesión. Si bien no pueden copiar su clave, pueden iniciar sesión en otras máquinas con ella. Asegúrese de comprender los riesgos y no utilice el reenvío de agentes para máquinas en las que no confía.

El siguiente comando utilizará el reenvío del agente SSH para abrir una conexión directa desde host1hasta host2. Esto tiene la ventaja de que la máquina que ejecuta el comando no está bloqueando la transferencia.

ssh -A host1 rsync -vuar /var/www host2:/var/www

3
+1 para explicar un caso de uso válido (donde el usuario remoto en host1 no tiene permisos en el servidor de destino); para la advertencia de seguridad importante (use el reenvío de puertos en -Dlugar de -Amoverse por la red en lugar de las restricciones clave); para explicar la ventaja; para que la orden sea corta; y realmente funciona Tenga en cuenta que es posible que deba especificar username@host1si es diferente del nombre de usuario local. Además, rsync realiza la verificación de la clave del host cuando se conecta al host2, por lo que la clave del host1 ya debería estar en ~ / .ssh / known_hosts en el host2 o el comando fallará.
Cedric Knight

Respuesta fenomenal, esto me ayudó a orquestar algunas cosas en TeamCity que no pude hacer antes (nb para otros usuarios de TeamCity, debe agregar la "Característica de compilación" llamada "Agente SSH" a su configuración de compilación antes de usar ssh -A, ver confluencia. jetbrains.com/display/TCD10/SSH+Agent ).
John Zwinck

12

Me gusta la respuesta de Roaima, pero los caminos son los mismos en ambos ejemplos, oscureciendo cuál es cuál. Hemos establecido que lo siguiente no funciona:

rsync -vuar host1:/host1/path host2:/host2/path

Pero esto sí (omití la dirección explícita de enlace de localhost de la -Ropción, ya que ese es el valor predeterminado):

ssh -R 50000:host2:22 host1 'rsync -e "ssh -p 50000" -vuar /host1/path localhost:/host2/path'

Tenga en cuenta que deberá tener las claves ssh configuradas correctamente entre los dos hosts remotos, con la clave privada en host1 y la clave pública en host2.

Para depurar la conexión, divídalo en dos partes y agregue el estado detallado:

localhost$ ssh -v -R 50000:host2:22 host1

Si esto funciona, tendrás un shell en host1. Ahora prueba el comando rsync de host1. Recomiendo hacer esto en una ventana diferente para que la información detallada de ssh no se mezcle con la información de estado de rsync:

host1$ rsync -e "ssh -p 50000" -vuar /host1/path localhost:/host2/path

En mi ejemplo, los caminos son fuente, destino. El rsyncse inicia en host1 con el objetivo en host2. (Podría haber pedido una aclaración en un comentario.)
roaima

1
Hubiera comentado, pero no puedes comentar en la publicación de otra persona sin una reputación de más de 50 años.
jaybrau

7

Reformateando la respuesta de roaima en la sintaxis de script bash (y agregando caracteres de continuación de línea '\' para mayor claridad) Elegí al azar el puerto 22000 ...

SOURCE_USER=user1
SOURCE_HOST=hostname1
SOURCE_PATH=path1

TARGET_USER=user2
TARGET_HOST=host2
TARGET_PATH=path2

ssh -l $TARGET_USER -A -R localhost:22000:$TARGET_HOST:22 \
$SOURCE_USER@$SOURCE_HOST "rsync -e 'ssh -p 22000' -vuar $SOURCE_PATH \
$TARGET_USER@localhost:$TARGET_PATH"

1
me parece que todo lo que has hecho es reemplazar sus nombres de host arbitrarios con variables?
Jeff Schaller

3
Sí, lo hice. Me agrega claridad sobre cuál es la máquina fuente, cuál es el objetivo y dónde van las rutas de origen y destino. Me tomó un tiempo resolver todo eso y no era obvio por simples nombres de host de marcador de posición.
David I.

La próxima vez, siéntase libre de mejorar la respuesta de otra persona directamente editándola.
roaima

Esta respuesta fue la solución para mí, ya que combina el reenvío de agente ssh (-A) con el túnel inverso (-R).
Camelthemammel

3

La forma ideal sería ejecutar rsyncuno de esos servidores. Pero si no desea ejecutar un script en el servidor remoto. Puede ejecutar un script en su sistema local y hacer un ssh y ejecutar el rsync allí.

ssh user@$host1 <<ENDSSH >> /tmp/rsync.out 2>&1 rsync -vuar /var/www host2:/var/www ENDSSH

Además, como ya sabrá, rysnc realiza una sincronización unidireccional. Si desea una sincronización bidireccional, puede consultar osync ( https://github.com/deajan/osync ). Lo uso y me pareció útil.


0

Solo como información adicional:

Si usa un host de salto para conectar las otras dos máquinas pero no pueden comunicarse entre sí directamente, puede usar sshfs como medio entre estas dos máquinas de la siguiente manera (en el host de salto):

$ mkdir ~/sourcepath ~/destpath
$ sshfs sourcehost:/target/dir ~/sourcepath
$ sshfs desthost:/target/dir ~/destpath
$ rsync -vua ~/sourcepath ~/desthpath

SSHFS proporciona las dos rutas en el host de salto y rsync gestiona la sincronización de los archivos como siempre (solo con la diferencia de que prácticamente se hace localmente).


1
Tenga en cuenta que el rendimiento será terrible. Esto se debe a que para detectar cambios, rsync leerá el archivo desde el servidor de origen, transfiriendo todo a través de la red. Dicho esto, si no puede hacer una transferencia directa, tendrá que comer esto si está utilizando rsync. Tampoco monte el destino, es innecesario y hará que rsync cambie algunos valores predeterminados porque cree que está hablando con un disco local.
Kevin Cox

0

Puede ejecutar un rsyncd (servidor) en una de las computadoras.

Este es el enfoque que estoy tomando, ya que no quiero usar ssh para permitir que el acceso 'fuente' (en redacción rsync) al 'destino' como root sin contraseña (como se requiere para usar el túnel SSH con rsync en un guión)

En mi caso, simplemente configuré un servidor rsyncd en la computadora de destino con un solo usuario permitido desde la PC fuente y usé rsync desde el lado fuente.

Funciona genial.


0

Intenta usar esto. Esto funciona para mi.

ssh src_user@src_host 'rsync -av /src/dir/location/ dest_user@dest_host:/dest/dir/loc/'

0

Un guión fácil de usar

A lo largo de los años, he hecho esto muchas veces con más o menos los mismos trucos que en cualquier otra respuesta aquí. Sin embargo, debido a que es muy fácil equivocarse en algunos detalles y pasar mucho tiempo resolviendo el problema, se me ocurrió el siguiente script:

  1. Facilita la especificación de todos los detalles (origen, destino, opciones)
  2. Prueba de forma incremental cada paso y brinda retroalimentación si algo sale mal, para que sepa qué solucionar.
  3. Funciona en casos donde ssh -Ano se propagan los datos de autenticación (no sé por qué sucede esto a veces, ya que la solución fue más fácil que encontrar la causa raíz)
  4. Finalmente hace el trabajo.

Cómo usar el guión

  1. Asegúrese de que puede enviar ssh a ambos hosts desde localhost sin escribir una contraseña.
  2. Establezca las variables en las primeras líneas del guión.
  3. Ejecutalo.

Cómo funciona

Como dije, usa los mismos trucos que en cualquier otra respuesta aquí:

  • La -Ropción de ssh para ssh de localhost a host1 mientras que al mismo tiempo configura un reenvío de puertos que luego permite que host1 se conecte a través de localhost a host2 ( -R localhost:$FREE_PORT:$TARGET_ADDR_PORT)
  • -AOpción de ssh para permitir la autenticación fácil del segundo canal ssh

¡Esto es complicado! ¿Hay alguna manera más fácil?

Al copiar todos o la mayoría de los bytes del origen al destino, es MUCHO más fácil de usar tar:

ssh $SOURCE_HOST "tar czf - $SOURCE_PATH" \
    | ssh $TARGET_HOST "tar xzf - -C $TARGET_PATH/"

La secuencia de comandos

#!/bin/bash
#-------------------SET EVERYTHING BELOW-------------------
# whatever you type after ssh to connect to SOURCE/TARGE host 
# (e.g. 1.2.3.4:22, user@host:22000, ssh_config_alias, etc)
# So if you use "ssh foo" to connect to SOURCE then 
# you must set SOURCE_HOST=foo
SOURCE_HOST=host1 
TARGET_HOST=host2 
# The IP address or hostname and ssh port of TARGET AS SEEN FROM LOCALHOST
# So if ssh -p 5678 someuser@1.2.3.4 will connect you to TARGET then
# you must set TARGET_ADDR_PORT=1.2.3.4:5678 and
# you must set TARGET_USER=someuser
TARGET_ADDR_PORT=1.2.3.4:5678
TARGET_USER=someuser

SOURCE_PATH=/mnt/foo  # Path to rsync FROM
TARGET_PATH=/mnt/bar  # Path to rsync TO

RSYNC_OPTS="-av --bwlimit=14M --progress" # rsync options
FREE_PORT=54321 # just a free TCP port on localhost
#---------------------------------------------------------

echo -n "Test: ssh to $TARGET_HOST: "
ssh $TARGET_HOST echo PASSED| grep PASSED || exit 2

echo -n "Test: ssh to $SOURCE_HOST: "
ssh $SOURCE_HOST echo PASSED| grep PASSED || exit 3

echo -n "Verifying path in $SOURCE_HOST "
ssh $SOURCE_HOST stat $SOURCE_PATH | grep "File:" || exit 5

echo -n "Verifying path in $TARGET_HOST "
ssh $TARGET_HOST stat $TARGET_PATH | grep "File:" || exit 5

echo "configuring ssh from $SOURCE_HOST to $TARGET_HOST via locahost"
ssh $SOURCE_HOST "echo \"Host tmpsshrs; ControlMaster auto; ControlPath /tmp/%u_%r@%h:%p; hostname localhost; port $FREE_PORT; user $TARGET_USER\" | tr ';' '\n'  > /tmp/tmpsshrs"

# The ssh options that will setup the tunnel
TUNNEL="-R localhost:$FREE_PORT:$TARGET_ADDR_PORT"

echo 
echo -n "Test: ssh to $SOURCE_HOST then to $TARGET_HOST: "
if ! ssh -A $TUNNEL $SOURCE_HOST "ssh -A -F /tmp/tmpsshrs tmpsshrs echo PASSED" | grep PASSED ; then
        echo
        echo "Direct authentication failed, will use plan #B:"
        echo "Please open another terminal, execute the following command"
        echo "and leave the session running until rsync finishes"
        echo "(if you're asked for password use the one for $TARGET_USER@$TARGET_HOST)"
        echo "   ssh -t -A $TUNNEL $SOURCE_HOST ssh -F /tmp/tmpsshrs tmpsshrs"
        read -p "Press [Enter] when done..."
fi

echo "Starting rsync"
ssh -A $TUNNEL $SOURCE_HOST "rsync -e 'ssh -F /tmp/tmpsshrs' $RSYNC_OPTS $SOURCE_PATH tmpsshrs:$TARGET_PATH"

echo
echo "Cleaning up"
ssh $SOURCE_HOST "rm /tmp/tmpsshrs"

tares genial cuando tienes una sola transferencia (no incremental) y tu transferencia se completa en una sola pasada. Por otro lado, rsynccon reenvío maneja reinicios y transferencias incrementales.
Roaima

1
Por supuesto @roaima: no considero el alquitrán equivalente. Dejé esta referencia para el día en que lo leeré para resolver un problema en el que rsync no será 100% necesario.
ndemou

-1

Es posible usar tarvia sshpara transferir los archivos:

ssh -n user1@host1 'tar jcf - -C /var/www .' | ssh user2@host2 'tar jxvf - -C /var/www'

Cambie el jparámetro (for tar) a zdos lugares si desea comprimir el archivo con gzip, en lugar de bzip2. Por lo general, bzip2tiene la compresión más alta que gzip, pero es más lenta, así que cámbiela según sus necesidades (consulte: bzip2 vs gzip ).

Relacionado: ¿Cómo copiar entre dos hosts remotos usando tar entubado en SSH desde un servidor remoto cuando está detrás de un firewall?


Alternativamente (para proteger el ancho de banda, debido a la compresión transparente) es posible usarlo sshfspara montar el sistema de archivos remoto como local y usarlo rsynccomo de costumbre, p. Ej.

$ sshfs user1@host1:/var/www /mnt
$ rsync -vuar /mnt user2@host2:/var/www

1
Montar el sistema de archivos localmente no ahorrará ancho de banda entre la fuente y la máquina local. Se va sin embargo ahorrar ancho de banda entre el local y de destino (ya que no está montado localmente). Usar rsync de esta manera solo tiene sentido si está tratando de ahorrar ancho de banda en el destino.
Kevin Cox
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.