文章目录
  1. 1. 无密码登录
  2. 2. 远程执行命令
  3. 3. SSH隧道
    1. 3.1. 配置SOCKS代理
    2. 3.2. 本地端口转发
    3. 3.3. 远程端口转发
  4. 4. 复制文件
  5. 5. 文件系统
  6. 6. 其它环境
    1. 6.1. Windows
    2. 6.2. Android
    3. 6.3. iOS
  7. 7. 参考资料

最近方才了解到,原来可以通过SSH以配置SOCKS代理的方式,不用开VPN便能够科学上网,于是便搜集了一些SSH的用法,以供未来参考。

无密码登录

只要把自己的公钥保存在远程主机上就可以了,如果本机尚未生成公私钥对(可以通过ls ~/.ssh查看是否存在以pub为扩展名的文件),可以通过ssh-keygen生成一个。之后把这个pub文件的内容全部复制到远程主机上的~/.ssh/authorized_keys中就能够实现无密码登录了。复制的过程也可以用以下命令实现:

1
ssh-copy-id user@remote.host.name

Mac上默认没有ssh-copy-id,可以通过以下命令安装:

1
brew install ssh-copy-id

远程执行命令

配置完无密码登录后,在远程主机上执行命令很简单,只要在最后面加一个字符串即可:

1
ssh remote.host.name "hostname"

如果命令很长,是个脚本,那就这么搞:

1
2
3
4
5
echo -e "ls\necho ggg" > cmd.txt
ssh remote.host.name "`cat cmd.txt`"
ssh remote.host.name < cmd.txt
cat cmd.txt | ssh remote.host.name

下面分享一段调试时查看远程日志的实用代码。如果你不知道自己的请求会被负载均衡到哪台服务器上去,可以试试下面这个ssh到所有服务器上执行tail -F的小脚本(当然也能用cat了):

tail_log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash
set -e
if [ -z $1 ]; then
echo "usage: $(basename $0) [log path] [optional grep message]"
echo "sample: $(basename $0) /abc/def/application.log* Execption"
exit 1
fi
log_path=$1
grep_message=${2-"''"}
hosts=(
"remote1.host.name"
"remote2.host.name"
"remote3.host.name"
)
remote_command="tail -F ${log_path} | grep --line-buffered ${grep_message}"
for host in "${hosts[@]}"
do
exec "ssh -fo StrictHostKeyChecking=no ${host} \"${remote_command}\" &"
done

当然看完日志以后,别忘了把ssh的进程杀掉:

kill_log
1
2
#!/bin/bash
kill -9 $(ps -ef | grep "[s]sh -fo StrictHostKeyChecking=no" | awk '{print $2}')

稍微解释一下以上的两个参数:

  • ssh -f: 让SSH在后台执行,之所以在后面再加一个&,是因为想让所有机器并行来tail日志。
  • ssh -o StrictHostKeyChecking=no: 这样就看不到由于第一次连接或是机器指纹变更而出现的Are you sure you want to continue connecting (yes/no)?

SSH隧道

配置SOCKS代理

超级简单:

1
ssh -D 9999 remote.host.name

这样便可以通过如下系统设置通过远程主机上网了(以mac为例):

浏览器代理也是一样(以chrome插件SwitchyOmega为例):

本地端口转发

如果你想让本地经由remote1访问remote2,可以这么做:

1
ssh -L 9999:remote2.host.name:80 remote1.host.name

-L后面的参数,表示本地端口:目标主机:目标主机端口,也就是说,往本地9999端口发出去的请求,会经由remote1传给remote2的80端口。为什么我们会需要这样的东东呢?原因可能有几种:

  • 本地访问不了remote2(或remote2的指定端口),但是本地可以访问remote1,并且remote1可以访问remote2。如果公司的网络分为几块,互相之间操作有限制,可能就需要一些remote1作为跳板/堡垒机(bastion)来做这样的脏活儿。
  • 被邪恶的防火墙挡住了去路的时候。
  • 希望能够比较安全的时候。
  • 有时候目标机器由于安全原因或其它原因,某个端口只能开放给自己。这时候就可以将remote1和remote2合而为一。例如,当Java调试所用的5050端口不对外开放时,就可以用以下命令让IDE在localhost的5050端口进行调试:
    1
    ssh -L 5050:localhost:5050 remote.host.name

中间的localhost是相对remote.host.name而言的,也就是它自己。

远程端口转发

在你的本地可以连通远程主机remote1和另一台远程主机remote2,而它们俩不能相互访问的情况下,如果你想让remote1能够访问remote2,就可以这么做:

1
ssh -R 9999:remote2.host.name:80 remote1.host.name

这样的话,remote1的本地用户便可以便可以通过你的9999端口,访问remote2的80端口了。相当于你把自己变成了一台堡垒机!如果你有权限在其它机器上运行远程端口转发的命令,那你也可以把它变成堡垒机,把你自己的客户机变成remote1了。

复制文件

SSH当然是可以用来复制文件的:

1
cat file | ssh -e none remote-host "cat > file"

其中的参数-e none,表示不转义任何字符。SSH默认会通过~来转义一些控制语句。

但是既然我们有scp,还用ssh图个什么,用专业工具吧。

文件系统

可以用sshfs来将远程的文件系统通过SFTP加载到本地。对于mac而言,可以用FUSE for macOS来实现。我还没有那样的需求,没试过,据说比较简单。有兴趣的读者可以自行尝试。

其它环境

Windows

Windows的话,你可以就得试试Putty了。

Android

用手机和平板来运维?你值得拥有!
JuiceSSH的基本功能时免费的,但是要想端口转发什么的就得收费了。用户体验很不错。
ConnectBot是完全免费的。

iOS

Prompt都说好,收费。

参考资料

SSH: More than secure shell
SSH原理与运用(二):远程操作与端口转发
25 Best SSH Commands / Tricks

文章目录
  1. 1. 无密码登录
  2. 2. 远程执行命令
  3. 3. SSH隧道
    1. 3.1. 配置SOCKS代理
    2. 3.2. 本地端口转发
    3. 3.3. 远程端口转发
  4. 4. 复制文件
  5. 5. 文件系统
  6. 6. 其它环境
    1. 6.1. Windows
    2. 6.2. Android
    3. 6.3. iOS
  7. 7. 参考资料