连接如下:
[Server1] <---> [my desktop] <---> [Server2]
服务器 1 和服务器 2 不允许直接相互通信(不要询问)。但是,我的桌面可以通过 ssh 访问这两个服务器。
我需要将文件从服务器1复制到服务器2。
传统上我一直使用 ssh+tar 黑客技术,例如:
ssh -q root@Server1 'tar -vzc /path/to/files ' | ssh -q root@Server2 'tar -vzx -C /'
这效果很好,但我想更进一步,通过我的桌面让 rsync 在两个服务器之间运行。
现在我知道我可以在一个终端中启动 ssh 端口转发隧道,然后在另一个窗口通过该隧道进行 rsync,但我不想在第二个终端上忙乱,也不想建立和破坏单独的端口转发隧道。我想要的是:
- 通过我的桌面使用一行命令将文件从 Server1 rsync 到 server2
- 只需一个命令行、一个终端窗口即可
- 我希望端口转发隧道仅在 rsync 命令的有效期内存在。
- 我不想 scp,我想 rsync。
有人有办法做到这一点吗?
编辑:这是有效的命令!大家干得好:1. 对于 rsa 密钥路径,不能使用 tildae,必须使用“/root/”。2. 这是最终的命令行:
ssh -R 2200:SERVER2:22 root@SERVER1 "rsync -e 'ssh -p 2200 -i /root/.ssh/id_rsa_ROOT_ON_SERVER2' --stats --progress -vaz /path/to/big/files root@localhost:/destination/path"
炸药爆炸了。
答案1
如果您乐意在中间机器上保留数据的副本,那么您可以简单地编写一个脚本,使用 server1 作为参考更新本地副本,然后使用本地副本作为参考更新 server2 上的备份:
#!/bin/sh
rsync user@server1:/path/to/stuff /path/to/loca/copy -a --delete --compress
rsync /path/to/loca/copy user@server2:/path/to/where/stuff/should/go -a --delete --compress
使用简单的脚本意味着您只需一个命令即可完成所有操作。如果数据敏感(您或公司中的其他人可能不希望您的笔记本电脑上有一份副本),那么这当然可能存在安全隐患。如果 server1 位于您的本地,那么您可以随后删除本地副本(因为下次可以通过本地 LAN 快速重建)。
构建隧道以便服务器可以更直接地有效地相互通信应该是可能的,如下所示:
- 在服务器 2 上将 /bin/sh 复制为 /usr/local/bin/shforkeepalive。使用符号链接而不是副本,则在修补 /bin/sh 的安全更新后,您无需更新它。
在服务器 2 上创建一个脚本,该脚本不执行任何操作,只是循环休眠几秒钟,然后回显少量文本,并使用 sh 的现在“副本”:
#!/usr/local/bin/shforkeepalive while [ "1" != "0" ]; do echo Beep! sleep 5 done
(
echo
可能不需要,因为即使 SSHd 配置为忽略来自 ssh 客户端的保持活动数据包,会话也不会空闲足够长的时间以致于超时)现在,您可以在笔记本电脑上编写一个脚本,在后台启动反向隧道,告诉 server1 使用 rsync 执行复制操作,然后通过终止循环脚本(这将关闭 SSH 会话)来终止反向隧道:
#!/bin/sh ssh user@server2 -L2222:127.0.0.1:22 /usr/local/bin/keepalivesctipt & ssh user@server1 -R2222:127.0.0.1:2222 rsync /path/to/stuff [email protected]:/destination/path/to/update -a --delete --compress -e 'ssh -p 2222' ssh user@server2 killall shforkeepalive
其运作方式如下:
- 第 1 行:标准“用于解释此脚本的命令”标记
- 第 2 行:启动带有反向隧道的 SSH 连接,并通过它运行 keepalive 脚本以保持其打开状态。结尾的 & 告诉 bash 在后台运行此脚本,这样下一行就可以运行而无需等待它完成
- 第 3 行:启动一个隧道,该隧道将连接到上面的隧道,以便 server1 可以看到 server2,并运行 rsync 来执行此安排的复制/更新
- 第 4 行:一旦 rsync 操作完成(因此第二个 SSH 调用返回),就终止保持活动脚本,这将终止第一个 ssh 会话。
这感觉不是特别干净,但应该可以工作。我还没有测试过上面的内容,所以你可能需要调整一下。将 rsync 命令设为 server1 上的单行脚本可能会有所帮助,因为它可以减少在调用 ssh 命令时对 ' 等字符进行转义的需要。
顺便说一句:您说“不要问”为什么两台服务器不能直接看到对方,但这通常是有充分理由的。我的主服务器和保存在线备份的服务器无法互相登录(并且所有用户的密码和密钥都不同)——这意味着如果其中一台被黑客入侵,它就不能被用作入侵另一台的简单途径,因此我的在线备份更安全(有人恶意从实时中删除我的数据,无法利用其更新备份的能力来删除所述备份,因为它没有直接接触主备份站点的能力)。两台服务器都可以连接到其他地方的中间服务器——实时服务器设置为在清晨将其备份(通过 rsync)推送到中间机器,备份服务器设置为(稍后允许第一步完成)连接并收集更新(再次通过 rsyc,然后进行快照步骤,以维护多个备份年龄)。这种技术可能也适用于您的情况,如果是这样,我会推荐它,因为它是一种更干净的做事方式。
编辑:将我的技巧与 Aaron 的技巧结合起来,以避免在 server2 上对 /bin/sh 的副本和单独的 keep-alive 脚本进行所有混乱的操作,您笔记本电脑上的这个脚本应该可以完成整个工作:
#!/bin/sh
ssh user@server2 -L2222:127.0.0.1:22 sleep 60 &
pid=$!
trap "kill $pid" EXIT
ssh user@server1 -R2222:127.0.0.1:2222 rsync /path/to/stuff [email protected]:/destination/path/to/update -a --delete --compress -e 'ssh -p 2222'
与上述一样,rsync 连接到 localhost:2222,它通过隧道转发到您的笔记本电脑的 localhost:2222,然后通过另一条隧道转发到 server2 的 localhost:22。
编辑2:如果您不介意 server1 拥有一个允许它直接与 server2 进行身份验证的密钥(即使在没有隧道的情况下无法看到 server2),您可以进一步简化:
#!/bin/sh
ssh user@server1 -R2222:123.123.123:22 rsync /path/to/stuff [email protected]:/destination/path/to/update -a --delete --compress -e 'ssh -p 2222'
其中 123.123.123.123 是 server2 的公共地址,可以用作复制粘贴的单行代码,而不是脚本。
答案2
答案3
为什么只有一行?使用一个小的 shell 脚本:
#!/bin/bash
# Run me on server1
# Create the port forward server1 -> desktop -> server2 (i.e.
# the first forward creates a second tunnel running on the desktop)
ssh -L/-R ... desktop "ssh -L/-R ... server2 sleep 1h" &
pid=$!
# Kill port forward process on exit and any error
trap "kill $pid" EXIT
rsync -e ssh /path/to/files/ root@localhost:/path/to/files/on/server2
据我所知,您可以将睡眠时间设置得更低;ssh
只要有人使用该频道,第一个就不会终止。