2.SSH命令及示例

  1. prerequisites
  2. 登录 Log-in
  3. 远程操作 Remote Control
  4. 隧道Tunnel
    1. 本地端口转发 Local Port Forwarding
    2. 远程端口转发 Remote Port Forwarding
  5. 代理 Proxy
  6. 其他 Others
  7. 参考

prerequisites

拥有两个 Hosts。可以通过 vagrant 启动虚拟机。本文中有两个 Hosts

  • my-host: 192.168.0.175
  • remote-host: 192.168.0.156,用户名:xiaojie

注:本章节不对 fingerprint 等校验细节进行讨论。

登录 Log-in

1
2
3
4
5
# 登录
$ ssh xiaojie@remote-host

# 指定端口号登录
$ ssh -p 2222 user@host

远程操作 Remote Control

1
2
$ ssh xiaojie@remote-host 'echo hello world'
hello world

隧道Tunnel

本地端口转发 Local Port Forwarding

场景1:

组长:我们在AWS云上部署了一个MySQL数据库,但是出于安全考虑,我们只允许云里面的应用服务访问这个数据库。

鸦鸦:那我们开发阶段,要怎么访问这个数据库?

组长:我们开发和产品的环境是不同,数据库也是不同的,因此开发阶段不需要太严格,可以让云上的一个 EC2 虚拟服务器开启 SSH 服务器功能,然后我们公司用一台电脑,Local Forwarding 云上SSH服务器,并且暴露出来,其他人就可以使用到数据库了。

(实际上,AWS不需要这样做,AWS可以使用VPN或者其他功能暴露云上服务。此处仅仅简单举例)

场景2

鸦鸦在它的电脑里,使用 vagrant 装了数据库,但是由于鸦鸦的笔记本没有连接以太网,所以决定不使用bridge。

同事:我不想装数据库,太卡了,我用你的就好啦。你给我你的 SSH用户密码,还有 vagrant的密钥,我登录一下。

同事先用 SSH将鸦鸦电脑的22端口,映射到它电脑的2222端口,然后再用2222端口开启一个SSH,访问vagrant。

示例一,访问 remote-host 本地服务

1
2
3
【remote-host】
$ curl localhost:4566
{"status": "running"}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
【local-host】
# -f 后台运行
# -N 不执行任何命令
# -L 本地端口转发
$ ssh -f -N -L 4567:localhost:4566 xiaojie@remote-host 
$ curl localhost:4567
{"status": "running"}

# 暴露到0.0.0.0端口,
$ ssh -f -N -L 0.0.0.0:4567:localhost:4566 xiaojie@remote-host
$ curl my-host:4567
{"status": "running"}

# 关闭SSH  (ubuntu 20)
# https://unix.stackexchange.com/questions/83806/how-to-kill-ssh-session-that-was-started-with-the-f-option-run-in-background
$ ps -lef | grep ssh | grep "4567" | awk "{print \$4}" |  xargs kill

示例二,访问 remote-host 能访问的服务。

1
2
3
#【remote-host】
$ curl site-A:4566
{"status": "running"}
1
2
3
4
#【my-host】
$ ssh -f -N -L 4567:site-A:4566 xiaojie@remote-host
$ curl localhost:4567
{"status": "running"}

示例三,双重SSH跳转

1
2
#【remote-host】
$ ssh sb@site-A-host
1
2
3
#【my-host】
$ ssh -f -N -L  2222:localhost:22 xiaojie@remote-host
$ ssh -p 2222 sb@site-A-host

远程端口转发 Remote Port Forwarding

场景1:

公司内部有一套共同使用的开发版本的服务。而某一天,服务2升级了,接着服务1发生了问题。

组长:鸦鸦,服务1好像有问题,你去看看怎么回事。

鸦鸦:emmm… 好像是服务1向服务2发送了一个请求,服务2回了一个错误的结果。

组长:那你停掉服务2,并且 remote port forward 上一个版本的服务2给服务1吧,看看是不是服务2升级了造成错误。

示例一

1
2
3
4
5
6
7
8
9
#【my-host】 使用 PyCharm启动了一个Django(Web页面),端口为8000
$ curl http://localhost:8000/
<!doctype html>
....

# 主机A 让 主机B(192.168.0.156)
$ ssh -f -N -R 8888:127.0.0.1:8000 xiaojie@remote-host
xiaojie@192.168.0.156's password:
...
1
2
3
4
5
6
#【remote-host】
$ curl http://localhost:8888/
<!doctype html>
....

# 证明了主机B可以访问到Django

示例二

默认情况下,我们需要修改下面的配置:

1
2
3
4
#【remote-host】
sudo sed -i '/^GatewayPorts/d' /etc/ssh/sshd_config 
echo 'GatewayPorts clientspecified' | sudo tee -a /etc/ssh/sshd_config
sudo service sshd restart

才能让我们访问到 【remote-host】。

1
2
3
4
5
#【my-host】
$ ssh -f -N -R 0.0.0.0:8888:localhost:8000 xiaojie@remote-host
$ curl http://remote-host:8888/
<!doctype html>
...

示例三

1
2
3
4
5
6
7
#【my-host】
$ ssh -f -N -R 0.0.0.0:2222:localhost:22 xiaojie@remote-host
xiaojie@192.168.0.156's password:
...
# 此时,将会登录主机A
$ ssh -p 2222 xiaojie@remote-host

代理 Proxy

在本地打开一个端口,然后当我们浏览器或者命令指定该端口去访问一些网站,就会跳转到【remote-host】上对指定的网站进行访问(代理访问网站)。

代里和隧道很类似。

1
2
3
#【remote-host】
$ curl localhost:4566
{"status": "running"}
1
2
3
4
#【my-host】
$ SSH -f -N -D 9899 xiaojie@remote-host
$ curl --socks5-hostname localhost:9989 localhost:4566
{"status": "running"}

其他 Others

1
2
#不检查fingerprint
$ ssh -o StrictHostKeyChecking=no username@127.0.0.1 

参考