ローカルシェルを使用して2つのリモートホスト間でファイルを転送したいのですが、次のように2つのリモートホストを指定すると、rsyncは同期をサポートしていないようです。
$ rsync -vuar host1:/var/www host2:/var/www
The source and destination cannot both be remote.
同様の結果を得るために使用できる他の回避策/コマンドは何ですか?
答え1
ご存知のように、リモートソースとリモートターゲットにはrsyncを使用できません。 2つのサーバーが互いに直接通信できないと仮定すると、SSHを使用してローカルシステムを介してトンネルを確立できます。
変える
rsync -vuar host1:/var/www host2:/var/www
あなたはこれを使うことができます
ssh -R localhost:50000:host2:22 host1 'rsync -e "ssh -p 50000" -vuar /var/www localhost:/var/www'
の最初のインスタンスは、のターゲットに対応するのソース/var/www
に適用されます。host1
localhost:/var/www
host2
気になる場合は、この-R
オプションはホスト1のポート50000でバックチャネルを設定します。このバックチャネルは(ローカルシステムを介して)ホスト2のポート22にマップされます。ホスト1からホスト2への直接接続はありません。
答え2
あるホストにログインしてから別のホストにコピーしたくない理由を話していないので、理由と回避策の1つを共有します。
どちらのホストにも別のコンピュータにログインするためのSSHキーがないため、あるコンピュータにログインしてから別のコンピュータにrsyncすることはできません。ログイン時に最初のホストが私のSSHキーを使用できるように、SSHエージェント転送を使用してこの問題を解決しました。
警告する:SSH転送により、ホストはログイン中にSSHキーを使用できます。キーをコピーすることはできませんが、それを使用して別のコンピュータにログインすることはできます。リスクを理解し、信頼できないシステムにプロキシ転送を使用しないでください。
次のコマンドは、SSHエージェント転送を使用してからhost1
直接接続を開きますhost2
。これの利点は、コマンドを実行するマシンが転送にボトルネックを引き起こさないことです。
ssh -A host1 rsync -vuar /var/www host2:/var/www
答え3
私はroaimaの答えが好きですが、両方の例で同じパスがあり、どちらが何であるか混乱しています。次の方法が機能しないことが確認されました。
rsync -vuar host1:/host1/path host2:/host2/path
しかし、はい(-R
デフォルトであるため、オプションからlocalhostの明示的なバインドアドレスを省略しました)。
ssh -R 50000:host2:22 host1 'rsync -e "ssh -p 50000" -vuar /host1/path localhost:/host2/path'
2つのリモートホスト間でSSHキーを正しく設定する必要があります(host1の秘密鍵とhost2の公開鍵)。
接続をデバッグするには、接続を2つの部分に分割し、詳細な状態を追加します。
localhost$ ssh -v -R 50000:host2:22 host1
これが機能すると、ホスト1にシェルがあります。ここで、Host1でrsyncコマンドを実行してみてください。詳細なSSH情報がrsyncステータス情報と混在しないように、別のウィンドウでこれを行うことをお勧めします。
host1$ rsync -e "ssh -p 50000" -vuar /host1/path localhost:/host2/path
答え4
使いやすいスクリプト
私はここの他の答えとほぼ同じトリックを使って長年にわたってこれを何度も実行しました。しかし、いくつかの詳細を間違って理解し、問題を解決するのに多くの時間を費やしやすいので、次のスクリプトを考えました。
- すべての詳細(ソース、宛先、オプション)を簡単に指定できます。
- 各ステップを段階的にテストし、問題が発生した場合は、フィードバックを提供して何を修正するかを知ることができます。
- 認証データを伝播できない状況の
ssh -A
修正 - やっと仕事を終えました。
スクリプトの使い方
- localhostから両方のホストにSSH経由で接続できることを確認してください。いいえパスワードを入力してください。
- スクリプトの最初の数行に変数を設定します。
- 実行してください。
どのように動作しますか?
私が言ったように、ここの他のすべての答えと同じトリックを使用します。
- SSHのオプション
-R
は、ポート転送の設定中にローカルホストからホスト1にsshを実行し、ホスト1がローカルホストを介してホスト2に接続できるようにすることです(-R localhost:$FREE_PORT:$TARGET_ADDR_PORT
)。 - SSHオプションを使用すると、
-A
2番目のSSHチャネルを簡単に認証できます。
私は複雑です!より簡単な方法がありますか?
ソースからターゲットに全体またはほとんどのバイトをコピーする場合遠く使いやすくなりましたtar
:
ssh $SOURCE_HOST "tar czf - $SOURCE_PATH" \
| ssh $TARGET_HOST "tar xzf - -C $TARGET_PATH/"
スクリプト
#!/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 [email protected] 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"